Overview
MenuBarManager manages a persistent NSStatusItem and NSPopover for the r2Vault menu bar widget. The popover uses .applicationDefined behavior to remain open even when the app loses focus, requiring explicit user interaction to dismiss.
Located at:
Fiaxe/Services/MenuBarManager.swift:17Type Definition
Initialization
The app’s view model, injected into the SwiftUI environment for the popover content.
Properties
statusItem
popover
viewModel
Setup Methods
setupStatusItem()
Configures the menu bar status item.Implementation Details
- Creates a status item with square dimensions (typically 22x22 points)
- Sets an SF Symbol icon:
arrow.up.to.line.compact(upload icon) - Configures accessibility description for VoiceOver
- Connects the button’s action to
togglePopover
setupPopover()
Configures the popover with SwiftUI content.Implementation Details
- Content size: 300x400 points
- Behavior:
.applicationDefined- popover won’t auto-dismiss when focus is lost - Animation: Enabled for smooth show/hide transitions
- Content: SwiftUI
MenuBarViewwrapped inAlwaysActiveHostingController
The
.applicationDefined behavior means the popover only dismisses when:- User clicks the status bar icon again
- User explicitly closes it via UI
- App calls
popover.performClose(nil)
- User clicks outside the popover
- App loses focus
- User switches to another app
Toggle Method
togglePopover()
Toggles the popover visibility when the status bar icon is clicked.Implementation Details
- Shows it relative to the status bar button’s bounds
- Positions it below the button (
.minYedge) - Activates the app, bringing it to the front
- Forces the popover window to become key window
- Calls
performClose(nil)to dismiss the popover
The
NSApp.activate(ignoringOtherApps: true) and makeKey() calls ensure the popover appears active and fully saturated even when other apps have focus.AlwaysActiveHostingController
A customNSHostingController subclass that prevents content desaturation:
Purpose
By default, AppKit windows become “inactive” when they lose key status, causing:- Colors to desaturate (appear washed out)
- Controls to appear disabled
- Reduced visual prominence
viewDidAppear() to force the window to remain key, maintaining:
- Full color saturation
- Active appearance
- Proper visual hierarchy
This is particularly important for menu bar apps that should maintain an “active” appearance even when the user interacts with other applications.
Popover Behavior Modes
AppKit provides several popover behaviors:| Behavior | Auto-dismiss on focus loss | Auto-dismiss on outside click | Use case |
|---|---|---|---|
.applicationDefined | No | No | Menu bar apps, persistent UI |
.transient | Yes | Yes | Tooltips, hints |
.semitransient | No | Yes | Inspectors, contextual UI |
.applicationDefined for maximum control.
SwiftUI Integration
The popover hosts SwiftUI content viaNSHostingController:
Usage Example
Lifecycle Management
Menu Bar Icon Guidelines
macOS Menu Bar Icon Best Practices:
- Use SF Symbols when possible (automatic dark mode support)
- Target size: 22x22 points (44x44 pixels @2x)
- Use template images (monochrome, system adjusts for light/dark mode)
- Keep designs simple and recognizable at small sizes
- Provide accessibility descriptions
Popover Positioning
The popover is positioned relative to the status bar button:.minY- Below (most common for menu bar).maxY- Above.minX- To the left.maxX- To the right
Related Components
- R2UploadService - File upload functionality
- MenuBarView (SwiftUI) - The SwiftUI content displayed in the popover
- AppViewModel - The app’s main view model