[Feature] Add separate progress bars status item#515
[Feature] Add separate progress bars status item#515johnyoonh wants to merge 2 commits intosteipete:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an optional second macOS menu bar status item that renders only the dual progress bars, so users can position bars independently from the provider icon when using merged icons.
Changes:
- Introduces new setting
menuBarShowsSeparateBarspersisted inSettingsStore/ defaults state. - Adds a lazily-created
separateBarsStatusItemand updates its visibility alongside the main merged status item. - Renders a bars-only icon via
applySeparateBarsIcon(phase:), including a provider-change refresh to reduce artifacts.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| Sources/CodexBar/StatusItemController.swift | Adds a second status item and integrates it into visibility + icon update flows. |
| Sources/CodexBar/StatusItemController+Animation.swift | Implements bars-only icon rendering for the new status item. |
| Sources/CodexBar/SettingsStoreState.swift | Extends settings defaults state with menuBarShowsSeparateBars. |
| Sources/CodexBar/SettingsStore.swift | Loads menuBarShowsSeparateBars from UserDefaults into defaults state. |
| Sources/CodexBar/SettingsStore+Defaults.swift | Adds getter/setter that persists menuBarShowsSeparateBars. |
| Sources/CodexBar/PreferencesDisplayPane.swift | Adds a preferences toggle row for the new display option. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private func updateIcons() { | ||
| // Avoid flicker: when an animation driver is active, store updates can call `updateIcons()` and | ||
| // briefly overwrite the animated frame with the static (phase=nil) icon. | ||
| let phase: Double? = self.needsMenuBarIconAnimation() ? self.animationPhase : nil | ||
| if self.shouldMergeIcons { | ||
| self.applyIcon(phase: phase) | ||
| self.applySeparateBarsIcon(phase: phase) | ||
| self.attachMenus() |
| /// Applies an icon showing only dual progress bars (no brand icon, no text) to the separate bars status item. | ||
| func applySeparateBarsIcon(phase: Double?) { | ||
| guard self.settings.menuBarShowsSeparateBars, | ||
| let button = self.separateBarsStatusItem?.button | ||
| else { return } |
| PreferenceToggleRow( | ||
| title: "Show separate progress bars", | ||
| subtitle: "Display an additional status item showing only progress bars (no icon or text).", | ||
| binding: self.$settings.menuBarShowsSeparateBars) | ||
| .disabled(!self.settings.mergeIcons) | ||
| .opacity(self.settings.mergeIcons ? 1 : 0.5) |
| let showsSeparateBars = self.settings.menuBarShowsSeparateBars && mergeIcons | ||
|
|
||
| // Update separate bars status item visibility | ||
| if showsSeparateBars { | ||
| if self.separateBarsStatusItem == nil { | ||
| self.separateBarsStatusItem = self.statusBar.statusItem(withLength: NSStatusItem.variableLength) | ||
| self.separateBarsStatusItem?.button?.imageScaling = .scaleNone | ||
| } | ||
| self.separateBarsStatusItem?.isVisible = anyEnabled || force |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6f999fe64c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let phase: Double? = self.needsMenuBarIconAnimation() ? self.animationPhase : nil | ||
| if self.shouldMergeIcons { | ||
| self.applyIcon(phase: phase) | ||
| self.applySeparateBarsIcon(phase: phase) |
There was a problem hiding this comment.
Refresh separate bars on every icon render path
applySeparateBarsIcon is wired only in updateIcons, but animation/blink render paths (updateAnimationFrame, updateAnimationState, and tickBlink in StatusItemController+Animation.swift) still call only applyIcon. As a result, when loading animation or blink effects are active, the separate bars item does not advance frames and can also stay blank on startup until another settings/store update triggers updateIcons after updateVisibility creates the item.
Useful? React with 👍 / 👎.
6f999fe to
f8a0339
Compare
There was a problem hiding this comment.
Pull request overview
Adds a new menu bar display option that, when using merged icons, can show the dual progress bars as a second independent NSStatusItem so users can position the bars separately from the provider icon.
Changes:
- Adds a new persisted setting (
menuBarShowsSeparateBars) and exposes it in Display preferences. - Creates/manages an optional second
NSStatusItemto render progress bars only. - Updates animation/icon refresh paths to render both the main merged item and the separate bars item, including a provider-change refresh to avoid artifacts.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| Sources/CodexBar/StatusItemController.swift | Adds state for an optional second status item and controls its visibility alongside existing items. |
| Sources/CodexBar/StatusItemController+Animation.swift | Renders the separate “bars-only” icon and hooks it into animation/tick updates. |
| Sources/CodexBar/SettingsStoreState.swift | Extends defaults state with the new menuBarShowsSeparateBars flag. |
| Sources/CodexBar/SettingsStore.swift | Loads the new flag from UserDefaults into SettingsDefaultsState. |
| Sources/CodexBar/SettingsStore+Defaults.swift | Adds a getter/setter that persists the new flag to UserDefaults. |
| Sources/CodexBar/PreferencesDisplayPane.swift | Adds the new Display toggle row for showing a separate progress-bars status item. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// Applies an icon showing only dual progress bars (no brand icon, no text) to the separate bars status item. | ||
| func applySeparateBarsIcon(phase: Double?) { | ||
| guard self.settings.menuBarShowsSeparateBars, | ||
| let button = self.separateBarsStatusItem?.button | ||
| else { return } | ||
|
|
||
| let primaryProvider = self.primaryProviderForUnifiedIcon() | ||
|
|
||
| // Force a refresh when the provider changes to avoid rendering artifacts | ||
| let providerChanged = self.lastSeparateBarsProvider != primaryProvider | ||
| if providerChanged { | ||
| // Clear the old image to force a clean render | ||
| button.image = nil | ||
| self.lastSeparateBarsProvider = primaryProvider | ||
| } |
| if showsSeparateBars { | ||
| if self.separateBarsStatusItem == nil { | ||
| self.separateBarsStatusItem = self.statusBar.statusItem(withLength: NSStatusItem.variableLength) | ||
| self.separateBarsStatusItem?.button?.imageScaling = .scaleNone |
| let mergeIcons = self.shouldMergeIcons | ||
| let showsSeparateBars = self.settings.menuBarShowsSeparateBars && mergeIcons | ||
|
|
| PreferenceToggleRow( | ||
| title: "Show separate progress bars", | ||
| subtitle: "Display an additional status item showing only progress bars (no icon or text).", | ||
| binding: self.$settings.menuBarShowsSeparateBars) | ||
| .disabled(!self.settings.mergeIcons) | ||
| .opacity(self.settings.mergeIcons ? 1 : 0.5) |
| /// Applies an icon showing only dual progress bars (no brand icon, no text) to the separate bars status item. | ||
| func applySeparateBarsIcon(phase: Double?) { | ||
| guard self.settings.menuBarShowsSeparateBars, | ||
| let button = self.separateBarsStatusItem?.button | ||
| else { return } | ||
|
|
||
| let primaryProvider = self.primaryProviderForUnifiedIcon() | ||
|
|
||
| // Force a refresh when the provider changes to avoid rendering artifacts | ||
| let providerChanged = self.lastSeparateBarsProvider != primaryProvider | ||
| if providerChanged { | ||
| // Clear the old image to force a clean render | ||
| button.image = nil | ||
| self.lastSeparateBarsProvider = primaryProvider | ||
| } | ||
|
|
||
| let showUsed = self.settings.usageBarsShowUsed | ||
| let snapshot = self.store.snapshot(for: primaryProvider) | ||
|
|
||
| var primary = showUsed ? snapshot?.primary?.usedPercent : snapshot?.primary?.remainingPercent | ||
| var weekly = showUsed ? snapshot?.secondary?.usedPercent : snapshot?.secondary?.remainingPercent | ||
| if showUsed, |
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- New toggle 'Show separate progress bars' in Display settings - When enabled, shows dual progress bars as separate menu bar item - Bars update independently from main provider icon - Users can drag to reposition in macOS menu bar - Fixed rendering artifacts when provider changes - Fixed animation sync: applySeparateBarsIcon now called in all animation paths (updateAnimationFrame, updateAnimationState, tickBlink) Implements requested feature for independent progress bar display. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
f8a0339 to
c885009
Compare
Summary
Adds a new display option to show dual progress bars as a separate menu bar status item, independent from the provider icon.
Changes
Use Cases
Testing
Note
This is a feature request implementation, not a bug fix.