Skip to content

feat: implemented initial version of hiding feature#744

Open
akramj13 wants to merge 2 commits into
FuJacob:mainfrom
akramj13:issue-742
Open

feat: implemented initial version of hiding feature#744
akramj13 wants to merge 2 commits into
FuJacob:mainfrom
akramj13:issue-742

Conversation

@akramj13

@akramj13 akramj13 commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

This pull request adds a new user preference to allow hiding Cotabby's menu bar icon while keeping the app running in the background. It introduces a toggle in Settings for controlling the visibility of the menu bar status item, ensures the app remains accessible by showing Settings when relaunched with the icon hidden, and persists this preference across launches. The implementation spans UI, model, persistence, and test updates.

Menu Bar Icon Visibility Preference:

  • Added a new isMenuBarIconVisible property to SuggestionSettingsData and SuggestionSettingsModel, with corresponding getter, setter, and persistence logic in SuggestionSettingsStore.
  • Updated CotabbyApp to conditionally insert the MenuBarExtra scene based on the new preference, using a SwiftUI binding that syncs with the settings model and persists changes.
  • Updated SettingsItem to support the new toggle, including title, icon, description, search terms, and categorization under the Appearance section.

App Behavior and Recovery:

  • Implemented applicationShouldHandleReopen in AppDelegate to show Settings if the app is reopened while the menu bar icon is hidden, ensuring users can always access the app's UI.

Testing and Persistence:

  • Added and updated tests to verify the new preference is persisted and restored correctly, and that the default is visible for new/existing users.

Solves #742

Greptile Summary

This PR adds a user preference to hide Cotabby's menu bar status item while keeping the suggestion pipeline running, with a recovery path via applicationShouldHandleReopen that opens Settings when the user relaunches the app with the icon hidden.

  • Model/persistence layer: isMenuBarIconVisible is added to SuggestionSettingsData, SuggestionSettingsModel, and SuggestionSettingsStore using the same pattern as existing boolean preferences, with a default of true so existing users are unaffected.
  • SwiftUI synchronization: CotabbyApp uses @AppStorage on the same UserDefaults key the store writes, so MenuBarExtra(isInserted:) reacts immediately when the settings model persists the change — no bespoke notification plumbing required.
  • Recovery and settings index: AppDelegate.applicationShouldHandleReopen correctly checks isMenuBarIconVisible before opening Settings, and guards on flag to avoid acting when Settings is already on-screen; SettingsItem and AppearancePaneView are updated with search terms, icon, and description.

Confidence Score: 5/5

Safe to merge — the change is well-scoped, defaults preserve existing user state, and the recovery path is correctly gated.

The feature is implemented consistently with existing boolean preferences across all layers (data, model, store, UI, tests). The @AppStorage/UserDefaults synchronization is sound, the applicationShouldHandleReopen logic correctly handles both the hidden-icon recovery case and the already-open-window guard, and no existing behavior is changed for users who never touch the new toggle.

No files require special attention.

Important Files Changed

Filename Overview
Cotabby/App/Core/CotabbyApp.swift Adds @AppStorage on the shared UserDefaults key and a Binding that syncs model + @AppStorage on write; the isInserted: API correctly drives MenuBarExtra insertion without extra observers.
Cotabby/App/Core/AppDelegate.swift Adds applicationShouldHandleReopen with correct early-exit when icon is visible (return true) and flag-guard to avoid acting when Settings is already on screen.
Cotabby/Support/SuggestionSettingsStore.swift Correctly uses object(forKey:) ?? true default so existing installs are unaffected, exposes the key as internal static for @AppStorage in CotabbyApp, and adds saveMenuBarIconVisible following existing save patterns.
Cotabby/UI/Settings/Panes/AppearancePaneView.swift Adds the toggle with description and system image; the word count toggle logically becomes a dead control when the icon is hidden (noted in a prior review comment).
CotabbyTests/SuggestionSettingsStoreTests.swift Adds default-visible test and a round-trip save/load assertion for isMenuBarIconVisible; coverage is consistent with other boolean preference tests.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant AppearancePaneView
    participant SuggestionSettingsModel
    participant SuggestionSettingsStore
    participant UserDefaults
    participant AppStorage as CotabbyApp @AppStorage
    participant MenuBarExtra

    User->>AppearancePaneView: Toggle "Show Cotabby in Menu Bar" → false
    AppearancePaneView->>SuggestionSettingsModel: setMenuBarIconVisible(false)
    SuggestionSettingsModel->>SuggestionSettingsStore: saveMenuBarIconVisible(false)
    SuggestionSettingsStore->>UserDefaults: set(false, key: menuBarIconVisible)
    UserDefaults-->>AppStorage: "KVO notification → isMenuBarIconVisible = false"
    AppStorage->>MenuBarExtra: isInserted binding getter returns false
    MenuBarExtra-->>User: Status item removed from menu bar

    Note over User, MenuBarExtra: Recovery path when icon is hidden

    User->>User: Relaunches Cotabby from Finder/Spotlight
    User->>AppDelegate: applicationShouldHandleReopen(_:hasVisibleWindows:)
    AppDelegate->>SuggestionSettingsModel: "check isMenuBarIconVisible == false"
    alt "No visible windows (flag = false)"
        AppDelegate->>AppDelegate: settingsCoordinator.showSettings()
        AppDelegate-->>User: Settings window appears
    else "Settings already visible (flag = true)"
        AppDelegate-->>User: return false (no duplicate window)
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant AppearancePaneView
    participant SuggestionSettingsModel
    participant SuggestionSettingsStore
    participant UserDefaults
    participant AppStorage as CotabbyApp @AppStorage
    participant MenuBarExtra

    User->>AppearancePaneView: Toggle "Show Cotabby in Menu Bar" → false
    AppearancePaneView->>SuggestionSettingsModel: setMenuBarIconVisible(false)
    SuggestionSettingsModel->>SuggestionSettingsStore: saveMenuBarIconVisible(false)
    SuggestionSettingsStore->>UserDefaults: set(false, key: menuBarIconVisible)
    UserDefaults-->>AppStorage: "KVO notification → isMenuBarIconVisible = false"
    AppStorage->>MenuBarExtra: isInserted binding getter returns false
    MenuBarExtra-->>User: Status item removed from menu bar

    Note over User, MenuBarExtra: Recovery path when icon is hidden

    User->>User: Relaunches Cotabby from Finder/Spotlight
    User->>AppDelegate: applicationShouldHandleReopen(_:hasVisibleWindows:)
    AppDelegate->>SuggestionSettingsModel: "check isMenuBarIconVisible == false"
    alt "No visible windows (flag = false)"
        AppDelegate->>AppDelegate: settingsCoordinator.showSettings()
        AppDelegate-->>User: Settings window appears
    else "Settings already visible (flag = true)"
        AppDelegate-->>User: return false (no duplicate window)
    end
Loading

Comments Outside Diff (1)

  1. Cotabby/UI/Settings/Panes/AppearancePaneView.swift, line 50-57 (link)

    P2 "Show Word Count in Menu Bar" toggle remains active when the icon is hidden

    When isMenuBarIconVisible is false the word-count badge has nowhere to render, yet the toggle stays enabled and its value is preserved. A user who hides the icon, notices the toggle is still "on," and tries to turn it off will have no visible effect — which reads as broken. Disabling the toggle (.disabled(!suggestionSettings.isMenuBarIconVisible)) when the icon is hidden would make the dependency explicit and avoid the confusion.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

    Fix in Codex Fix in Claude Code

Reviews (2): Last reviewed commit: "fix: avoid reopening visible settings wi..." | Re-trigger Greptile

Comment thread Cotabby/App/Core/AppDelegate.swift

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds a new persisted preference that lets users hide Cotabby’s menu bar status item while keeping the app running, with a reopen “recovery” path that surfaces Settings when the user relaunches Cotabby without the icon visible.

Changes:

  • Introduces isMenuBarIconVisible across settings data/model/store and persists it to UserDefaults.
  • Conditionally inserts/removes the MenuBarExtra scene via a scene-level @AppStorage projection.
  • Implements reopen handling to open Settings when the app is reopened while the menu bar icon is hidden, plus updates/expands test coverage.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
Cotabby/App/Core/CotabbyApp.swift Makes the menu bar scene optional via MenuBarExtra(isInserted:) driven by @AppStorage.
Cotabby/App/Core/AppDelegate.swift Adds applicationShouldHandleReopen recovery behavior when the icon is hidden.
Cotabby/Models/SuggestionSettingsData.swift Extends the durable settings payload with isMenuBarIconVisible.
Cotabby/Models/SuggestionSettingsModel.swift Adds published state + setter that persists isMenuBarIconVisible.
Cotabby/Support/SuggestionSettingsStore.swift Adds the new defaults key, load defaulting behavior, and save plumbing.
Cotabby/UI/Settings/Panes/AppearancePaneView.swift Adds the Settings toggle and binding for menu bar icon visibility.
Cotabby/UI/Settings/SettingsIndex.swift Adds a new searchable SettingsItem entry for the toggle.
CotabbyTests/SuggestionSettingsModelTests.swift Extends model round-trip tests to include the new preference.
CotabbyTests/SuggestionSettingsStoreTests.swift Adds default + round-trip persistence tests for the new preference.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +55 to +62
private var menuBarIconVisibilityBinding: Binding<Bool> {
Binding(
get: { isMenuBarIconVisible },
set: { visible in
isMenuBarIconVisible = visible
appDelegate.suggestionSettings.setMenuBarIconVisible(visible)
}
)
@akramj13 akramj13 requested a review from FuJacob June 19, 2026 06:28
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.

2 participants