fix(BaseUI): suppress new-message pop-up while a menu is on screen (#11373)

Menus share the single global banner slot with notification pop-ups
(Screen::showOverlayBanner overwrites message, options, and callback
unconditionally), so a "New Message" banner arriving mid-menu destroyed
the open menu and stole its input.

Add NotificationRenderer::isMenuShowing() — true when the active overlay
is interactive (a menu with options, or any picker/keyboard/pairing-PIN
type) rather than a plain text banner — and skip the new-message banner
in handleNewMessage() while such an overlay is up. Screen wake and
hasUnreadMessage behavior are unchanged, and a new message can still
replace an earlier plain banner.


Claude-Session: https://claude.ai/code/session_01PSAouemtAihV5P87AgCadu

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jason P <applewiz@mac.com>
This commit is contained in:
Jonathan Bennett
2026-08-10 02:30:37 +00:00
committed by GitHub
co-authored by Claude Jason P
parent e958f7bdef
commit 2e958821f9
3 changed files with 14 additions and 1 deletions
+5 -1
View File
@@ -14,6 +14,7 @@
#include "graphics/TFTColorRegions.h"
#include "graphics/TFTPalette.h"
#include "graphics/TimeFormatters.h"
#include "graphics/draw/NotificationRenderer.h"
#include "graphics/emotes.h"
#include "main.h"
#include "meshUtils.h"
@@ -1128,6 +1129,9 @@ void handleNewMessage(OLEDDisplay *display, const StoredMessage &sm, const mesht
if (packet.from != 0) {
hasUnreadMessage = true;
const bool suppressBanner = cannedMessageModule && cannedMessageModule->isFreeTextActive();
// Don't let the pop-up clobber a menu/picker the user is interacting with; the wake below
// still happens so a message can light the screen back up.
const bool menuShowing = NotificationRenderer::isMenuShowing();
// Determine if message belongs to a muted channel
bool isChannelMuted = false;
@@ -1222,7 +1226,7 @@ void handleNewMessage(OLEDDisplay *display, const StoredMessage &sm, const mesht
screen->setOn(true);
}
if (!suppressBanner) {
if (!suppressBanner && !menuShowing) {
screen->showSimpleBanner(banner, inThread ? 1000 : 3000);
}
}
@@ -1216,5 +1216,13 @@ bool NotificationRenderer::isOverlayBannerShowing()
return strlen(alertBannerMessage) > 0 && (alertBannerUntil == 0 || millis() <= alertBannerUntil);
}
bool NotificationRenderer::isMenuShowing()
{
// A menu, picker, keyboard, or pairing-PIN overlay - anything interactive, as opposed to a plain
// informational text banner (which has no options and type text_banner). Menus don't set a
// notificationType of their own, so options are the only thing distinguishing them.
return isOverlayBannerShowing() && (alertBannerOptions > 0 || current_notification_type != notificationTypeEnum::text_banner);
}
} // namespace graphics
#endif
+1
View File
@@ -53,6 +53,7 @@ class NotificationRenderer
static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
static bool isOverlayBannerShowing();
static bool isMenuShowing();
static graphics::notificationTypeEnum current_notification_type;
};