Skip to content

Design: dedicated Tray settings page and status menu grouping (#288, #290) - #296

Merged
skyswordw merged 2 commits into
mainfrom
claude/288-tray-settings-design-21beb4
Nov 6, 2026
Merged

skyswordw merged 2 commits into
mainfrom
claude/288-tray-settings-design-21beb4

Conversation

@skyswordw

@skyswordw skyswordw commented Nov 5, 2026 •

Copy link
Copy Markdown
Member

Integrated validation

Merged into main in sequence #295–#300. Final main commit 7c5393672d028f31bc76f83911a02e1407a53cf7 has the same file tree as tested integration commit 8fb4dda. Full local validation passed 687 tests in 102 suites with zero failures/skips, 0/1,261 missing zh-Hans strings, unchanged generated plists and clean diff checks. Bounded native CUA/AX draft creation and Search Clear/Close checks passed, including independent ZIP byte verification; this is not VoiceOver testing. See the review comment for scope and remaining native checks. Final main CI and the integrated #300 snapshot run supersede cancelled intermediate reruns.

Claude Code's visual design for #288 (dedicated Tray settings page) and the grouping/copy review for #290 (status-item menu). Functional foundation: #295.

Ownership per AGENTS.md: this PR is presentation only (layout, hierarchy, copy, zh-Hans). Functional state, routing, lifecycle, tests and acceptance stay with Codex / Grok Bot in #295. This PR claims no functional or native-runtime acceptance.

#288 — Settings › Tray

The page follows the #162 grouped-form conventions and the Actions page's "master switch first" pattern:

  1. Enable Tray — subtitle says what the Tray is for. The footer changes with the state and gives the residency rule:
    • on: closing Stow's last window keeps Stow running without a Dock icon so the Tray stays ready;
    • off: closing Stow's last window quits Stow once its work finishes.
      Both say opening at login is set in Finder & Permissions (still a separate setting).
  2. Showing and Hiding — the menu-bar icon (subtitle: click shows/hides, Control-click opens Stow's menu), drag reveal (subtitle restored from the old General section: drag up to the icon, or to the right edge without it), and ⌥⌘T as a read-only row (it's fixed; it's also in the Window menu). The footer keeps the Claude Code: clarify Tray Keep Open states and refine dismissal motion #282 Keep Open sentence (outside click/app switch hides it; the pin keeps it open). When the icon and drag reveal are both off, the footer adds a line saying ⌥⌘T still shows the Tray.
  3. Appearance — Border colour with the colour swatches the old General section had.

No idle timer or slider, per the user's decision in #286.

While Tray is off, sections 2–3 are disabled and their text goes tertiary. A grouped form greys a disabled switch but leaves its title at full strength, so without this the dependent rows didn't look inactive. Values are kept for when Tray is turned back on.

Light Dark
Tray on
Tray off

zh-Hans, Tray on with icon and drag reveal both off (shows the extra footer line):

Captured with scripts/snapshot.sh settings <look> "" -StowSettingsPane tray -tray.enabled '<true|false/>' -tray.pinned '<false/>' (argument domain only; no real preferences changed). The Settings window isn't key in snapshot runs, so the switches show the inactive-window tint.

#290 — status-item menu

Kept as a plain native NSMenu; only the grouping changed, to match an app menu (what it opens, then Settings, then Quit on its own):

Open Tray
Open Stow
Create Archive…
───────────────
Settings…
───────────────
Quit Stow
  • Ellipses: Create Archive… opens a draft that needs more input, and Settings… opens a window, so both keep the ellipsis. Open Tray / Open Stow / Quit Stow don't take one.
  • Labels: kept Implement optional Tray residency and new archive drafts #295's names. "Open Tray" / "Open Stow" read as a parallel pair, and neither is ambiguous. "Settings…" stays generic even though it opens the Tray page, as menu-extra conventions expect.
  • No key equivalents are shown. ⌘, and ⌥⌘T only work while Stow is in front, so showing them in a menu-bar menu would suggest global shortcuts that don't exist.
  • zh-Hans was already right: 打开托盘 / 打开 Stow / 创建压缩包… / 设置… / 退出 Stow.

I couldn't capture the open menu: this environment has no Screen Recording permission, and the snapshot harness can't pop up a status-item menu.

Functional contracts and behaviour changes

  • One behaviour-adjacent change: the Enable switch now writes through app.tray.setEnabled(_:) instead of a separate @AppStorage("tray.enabled") binding, and reads app.tray.isEnabled. Same key, same effect (setEnabled writes SettingsKeys.trayEnabled, then applySettings()), but the view no longer holds a second copy of the state. Reset This Page / Reset All still update it through the existing UserDefaults observer.
  • SettingsKeys, the .tray deep link, migration, the menu actions and their validation are unchanged. Menu tracking still runs inside beginRelatedInteraction / endRelatedInteraction.
  • No new state or animation. Standard controls keep their keyboard access, Reduce Motion/Transparency and Increase Contrast behaviour, and accessibility names come from the visible labels. Dedicated VoiceOver testing stays deferred under Accessibility: AX label recursion crashes archive activation and Browser failure states #93.
  • Strings: 9 new zh-Hans strings. Two obsolete keys (Tray border and the old "When enabled, Tray stays available…" footer) were removed from the catalog. Resources/Localizable.xcstrings is shared with the sibling design PRs, so expect a trivial merge there.

Checks

  • xcodebuild … build: passes
  • xcodebuild … test: 685 tests in 102 suites passed. The first run hit the known "test runner hung before establishing connection" problem with derived data under ~/Downloads; I reran with -derivedDataPath ~/Library/Developer/Xcode/DerivedData/…
  • scripts/check-localizations.sh zh-Hans: 0 of 1239 strings missing

DESIGN.md: the Settings table now lists Tray under Interaction (it's no longer in General), the page count is now thirteen, a Tray-page bullet describes the hierarchy and the status menu, and the #282 note points to Settings › Tray.

🤖 Generated with Claude Code

…290)

Settings › Tray puts Enable Tray first, with a footer that says what
closing the last window does in each state, then Showing and Hiding
(menu-bar icon, drag reveal, the fixed ⌥⌘T, the Keep Open note) and
Appearance (border colour with swatches). Rows under the switch are
disabled and dimmed while Tray is off; their values are kept. The
switch now goes through TrayController.setEnabled instead of a second
@AppStorage binding. No idle timer.

The status-item menu stays a plain NSMenu, regrouped as an app menu:
Open Tray, Open Stow, Create Archive… | Settings… | Quit Stow.

Adds zh-Hans for every new string and updates DESIGN.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@skyswordw skyswordw left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Functional integration review completed with no blocking findings. The Enable binding uses the authoritative Tray controller, subordinate settings preserve their values while disabled, reset/migration coverage passes, and native menu grouping keeps the existing routing and related-interaction scope. Claude Code owns the presentation/motion; this review covers behavior and integration.

Validated in the combined #295–#300 tree: 687 tests passed with zero failures/skips; 0/1,261 missing zh-Hans translations; generated plists unchanged. The original physical status-menu acceptance is still not established by model tests, so #290 remains open.

@skyswordw
skyswordw changed the base branch from codex/tray-functional-followups to main November 6, 2026 00:45
@skyswordw
skyswordw merged commit dbd6250 into main Nov 6, 2026
0 of 3 checks passed
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