Fix floating bar visibility issues with queued notifications#7806
Conversation
…n disabled When the floating bar is disabled, notifications temp-show it and dismissNotificationAndAdvanceQueue re-hides it afterward via the notificationWasTemporarilyShown flag. Presenting a queued notification clobbered that flag (the window is already visible mid-chain), so once two or more notifications chained, the final dismiss skipped the re-hide and the bar stayed on screen permanently despite the toggle being off. Preserve the flag for the duration of the notification chain; it is still reset when the chain ends or consumed by the re-hide. Fixes BasedHardware#6972 https://claude.ai/code/session_01T6yzmd3o4uxxo133uepsF4
…ile bar disabled Review follow-up: a notification queued during an AI conversation is flushed by closeAIConversation's completion while the window is still visible, so the temp-show flag was never armed and the unconditional orderOut swallowed the notification instantly. Arm the re-hide whenever a notification is presented with the bar disabled, and skip the close-path orderOut when a flushed notification is on screen — its dismissal re-hides the bar. https://claude.ai/code/session_01T6yzmd3o4uxxo133uepsF4
There was a problem hiding this comment.
Pull request overview
Fixes an edge case where the floating control bar could remain permanently visible even when the user has disabled “Show floating bar”, due to queued notification presentation/reset logic and an AI-conversation-close interaction that could hide a just-flushed notification.
Changes:
- Preserve
notificationWasTemporarilyShownacross a queued-notification chain so the bar is re-hidden after the final notification dismisses when the bar is disabled. - Prevent
closeAIConversation()from immediately hiding the window when a queued notification was just flushed and is currently being shown. - Add an unreleased changelog entry for the user-facing fix.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
desktop/Desktop/Sources/FloatingControlBar/FloatingControlBarWindow.swift |
Fixes notification-chain flag handling and avoids swallowing flushed notifications on AI conversation close. |
desktop/CHANGELOG.json |
Documents the fix in the unreleased section. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Greptile SummaryFixes a floating-bar visibility regression (#6972) where the bar would stay permanently on-screen when "Show floating bar" is off and two notifications arrive within the same 6-second display window. The root cause was that
Confidence Score: 4/5The change is a focused two-site control-flow fix inside a single class; no interface or data-model changes. The flag lifecycle is traced correctly through every chain path. Both edits are narrow and self-contained. The removal of the explicit desktop/Desktop/Sources/FloatingControlBar/FloatingControlBarWindow.swift — specifically the interaction between Important Files Changed
Sequence DiagramsequenceDiagram
participant N as Notification Emitter
participant M as FloatingControlBarManager
participant W as FloatingControlBarWindow
Note over M: isEnabled = false
N->>M: enqueueNotification(A)
M->>M: presentNotification(A)
Note over M: !window.isVisible → arm flag, orderFrontRegardless
M->>W: showNotification(A)
N->>M: enqueueNotification(B) [within 6s]
M->>M: window has currentNotification → pendingNotifications.append(B)
Note over M: 6s timer fires
M->>M: dismissNotificationAndAdvanceQueue()
M->>W: dismissNotification()
M->>M: pendingNotifications not empty → presentNotification(B)
Note over M: (NEW) !isEnabled → keep flag true, skip orderFrontRegardless
M->>W: showNotification(B)
Note over M: 6s timer fires
M->>M: dismissNotificationAndAdvanceQueue()
M->>W: dismissNotification()
Note over M: pendingNotifications empty
Note over M: (NEW) flag still true → orderOut ✓
M->>W: orderOut(nil)
M->>M: "notificationWasTemporarilyShown = false"
Reviews (1): Last reviewed commit: "fix(desktop): cover notifications flushe..." | Re-trigger Greptile |
Summary
Fixes #6972 — with "Show floating bar" turned off, the floating bar reappears during normal use and then stays on screen permanently.
Root cause
When the bar is disabled, floating-bar notifications (proactive assistants, trial banner) still surface it temporarily by design:
presentNotificationsetsnotificationWasTemporarilyShown = true, anddismissNotificationAndAdvanceQueuere-hides the bar when the notification goes away.That flag was clobbered mid-chain: when a queued notification is presented (any notification arriving during another's 6-second display window queues), the window is already visible from the temp-show, so the
elsebranch resetnotificationWasTemporarilyShown = false. When the last notification in the chain dismissed, the re-hide condition was false — and the bar stayed visible forever despite the toggle being off.This matches the report exactly ("continue using the application for a period of time… the bar just appears forever after a moment"): proactive assistants regularly emit notification bursts (e.g. focus-lost/regained), so two notifications chaining is a routine occurrence. The sibling path
showTemporarily()was already patched for this same symptom; the notification-queue path was missed.Fix
Preserve the flag for the duration of the notification chain — it now means "the bar was hidden when this chain started". It is still consumed by the re-hide or reset when the chain ends, so all other lifecycle paths are unchanged:
false, no behavior change.!isEnabled.isEnabledis rechecked at chain end, bar correctly stays up.Follow-up (review feedback): a notification queued during an active AI conversation is flushed by
closeAIConversation's completion while the window is still visible, so the temp-show flag was never armed and the unconditionalorderOut(nil)hid the just-presented notification instantly. Two complementary changes: presenting a notification while the bar is disabled now always armsnotificationWasTemporarilyShown(even if the window is visible), and the close path skipsorderOutwhen a flushed notification is on screen — its dismissal re-hides the bar instead.Also appends the user-facing entry to
unreleasedindesktop/CHANGELOG.json.Testing
notificationWasTemporarilyShownand the show/hide lifecycle paths (show,hide,showTemporarily,openAIInput*, snooze, conversation close) — details above.