Skip to content

Fix collapsed floating bar stretching on notification#5843

Merged
kodjima33 merged 2 commits intomainfrom
fix-floating-bar-collapsed-width
Mar 19, 2026
Merged

Fix collapsed floating bar stretching on notification#5843
kodjima33 merged 2 commits intomainfrom
fix-floating-bar-collapsed-width

Conversation

@kodjima33
Copy link
Copy Markdown
Collaborator

Summary

  • Bar chrome now uses intrinsic width when collapsed instead of maxWidth: .infinity
  • Prevents the small pill from stretching to notification/window width when a floating bar notification appears
  • Only stretches to full width when actually expanded (hovering, AI conversation, voice listening)

Test plan

  • Collapsed bar stays as small pill when notification appears below it
  • Hover still expands bar to full width correctly
  • AI conversation still renders at full width
  • Voice listening still renders at full width

🤖 Generated with Claude Code

kodjima33 and others added 2 commits March 19, 2026 02:05
…toring

- Add periodic permission recheck every 60 seconds during capture
- Stop monitoring gracefully when permission is revoked
- Send permissionLost event for UI notification
- Prevents silent data loss when user revokes permission via System Settings
- Fixes #5792
The bar chrome was using `frame(maxWidth: .infinity)` unconditionally,
causing the dark background to stretch to fill the window width when a
notification expanded the window. Now only stretches when actually
expanded (hovering, AI conversation, or voice listening).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@kodjima33 kodjima33 merged commit ff46a89 into main Mar 19, 2026
2 checks passed
@kodjima33 kodjima33 deleted the fix-floating-bar-collapsed-width branch March 19, 2026 20:15
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 19, 2026

Greptile Summary

This PR makes two independent fixes: a SwiftUI layout fix for the floating control bar pill, and a runtime screen recording permission-revocation detector for the proactive assistants plugin.

  • FloatingControlBarView.swift: Introduces the barNeedsFullWidth computed property (isHovering || showingAIConversation || isVoiceListening) and gates maxWidth: .infinity on the bar chrome behind it. Previously the frame was unconditionally maxWidth: .infinity, causing the small pill to stretch to window/notification width whenever a notification appeared. Removing isShowingNotification from the corner-radius condition is intentional — the pill correctly stays at radius 5 while the notification card renders with its own radius 18 background.
  • ProactiveAssistantsPlugin.swift: Adds a 60-second periodic permission recheck inside captureFrame(). On each fire, if 60 seconds have elapsed, ScreenCaptureService.checkPermission() is called; a false result stops monitoring and emits a permissionLost event. This correctly addresses the silent-failure scenario described in issue Desktop: No screen recording permission monitoring — silent degradation #5792.

Confidence Score: 4/5

  • PR is safe to merge; the UI fix is clean and the permission check logic is correct, with one minor style concern about a blocking call on the main actor.
  • Both changes are narrowly scoped and address real bugs. The layout fix is a straightforward SwiftUI frame constraint change with no regressions. The permission-check addition is logically correct. The only concern is that checkPermission() calls process.waitUntilExit() synchronously on @MainActor every 60 seconds, which could briefly block the UI — but this is a pre-existing pattern in the same file and the impact is bounded.
  • desktop/Desktop/Sources/ProactiveAssistants/ProactiveAssistantsPlugin.swift — the blocking checkPermission() call warrants a follow-up to move it off the main thread.

Important Files Changed

Filename Overview
desktop/Desktop/Sources/FloatingControlBar/FloatingControlBarView.swift Introduces barNeedsFullWidth computed property to gate maxWidth: .infinity on the bar chrome to hover/AI/voice states only, preventing the collapsed pill from stretching when a notification appears. The removal of isShowingNotification from the corner-radius condition is intentional and consistent with the fix. No issues found.
desktop/Desktop/Sources/ProactiveAssistants/ProactiveAssistantsPlugin.swift Adds a 60-second periodic screen recording permission recheck inside captureFrame(). Logic is sound and addresses permission-revocation detection. However, checkPermission() ultimately calls process.waitUntilExit() synchronously on the @MainActor, which may briefly block the main thread every 60 seconds.

Sequence Diagram

sequenceDiagram
    participant Timer as captureTimer
    participant CF as captureFrame()
    participant PC as ScreenCaptureService.checkPermission()
    participant SC as screencapture CLI (subprocess)
    participant SM as stopMonitoring()

    Timer->>CF: fires (every ~1s)
    CF->>CF: now.timeIntervalSince(lastPermissionCheckTime) >= 60?
    alt Permission check due (every 60s)
        CF->>PC: checkPermission() [blocks @MainActor]
        PC->>SC: Process.run() + waitUntilExit()
        SC-->>PC: exit code + file
        PC-->>CF: Bool (granted)
        alt Permission revoked
            CF->>CF: sendEvent("permissionLost")
            CF->>SM: stopMonitoring()
            CF-->>Timer: return
        end
    end
    CF->>CF: continue normal capture logic
Loading

Last reviewed commit: "Fix collapsed floati..."

let now = Date()
if now.timeIntervalSince(lastPermissionCheckTime) >= permissionCheckInterval {
lastPermissionCheckTime = now
let permissionGranted = ScreenCaptureService.checkPermission()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Blocking main thread with checkPermission()

ScreenCaptureService.checkPermission() internally calls testCapturePermission(), which launches a /usr/sbin/screencapture process and calls process.waitUntilExit() — a synchronous, blocking call. Because ProactiveAssistantsPlugin is @MainActor and captureFrame() runs on the main thread, this blocks the UI thread for the full duration of the screenshot every 60 seconds, which can cause noticeable UI jank.

Consider offloading the check to a background task:

let permissionGranted = await Task.detached(priority: .utility) {
    ScreenCaptureService.checkPermission()
}.value

This pattern is already safe here since you immediately resume on @MainActor after the await.

Glucksberg pushed a commit to Glucksberg/omi-local that referenced this pull request Apr 28, 2026
…5843)

## Summary
- Bar chrome now uses intrinsic width when collapsed instead of
`maxWidth: .infinity`
- Prevents the small pill from stretching to notification/window width
when a floating bar notification appears
- Only stretches to full width when actually expanded (hovering, AI
conversation, voice listening)

## Test plan
- [ ] Collapsed bar stays as small pill when notification appears below
it
- [ ] Hover still expands bar to full width correctly
- [ ] AI conversation still renders at full width
- [ ] Voice listening still renders at full width

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant