Skip to content

Build experience themes and overhaul Settings window UX - #286

Open
Yankj wants to merge 25 commits into
erha19:mainfrom
Yankj:feat/experience-themes
Open

Build experience themes and overhaul Settings window UX#286
Yankj wants to merge 25 commits into
erha19:mainfrom
Yankj:feat/experience-themes

Conversation

@Yankj

@Yankj Yankj commented Aug 26, 2026

Copy link
Copy Markdown

Why

Using the Settings window in daily work exposed two connected problems.

First, the window did not behave like a current macOS Settings window:

  • dragging could feel delayed because the custom content had to recognize the gesture first;
  • simulated traffic lights did not match the system layout and could move with scrollable content;
  • the borderless/translucent composition could leave a dark edge around the panel;
  • switching repeatedly between Display, Statistics, Sound, and other heavier categories could take 1–2 seconds before the selection visibly responded;
  • the sidebar treatment was too generic to preserve PingIsland's existing identity while also offering a genuinely native macOS variant.

Second, the original theme work was still closer to a collection of local visual/audio presets than a reusable experience architecture. Confirmation actions and new feedback moments could drift between views, PingIsland native and macOS styling were easy to conflate, and Pixel did not yet have a complete visual + interaction + sound reference implementation.

Visual review of the first Pixel reference renders also caught a compositing issue: the pixel grid was attached as a root overlay, so it rendered above labels, icons, cards, previews, and controls. Game Boy Olive compounded that issue by using closely related olive tones for both surfaces and foreground content, flattening the hierarchy and making the whole screen look green-tinted.

These concerns share the Settings presentation boundary, so this PR now integrates the complete history of #285 and supersedes its standalone scope. Keeping them together lets the native window shell be fixed once while each experience theme owns only the content it should actually customize.

What changed

1. Native Settings window and responsive navigation

  • Replace the borderless/custom window controls with a titled, closable, miniaturizable, resizable, full-screen-capable AppKit window.
  • Use the real macOS traffic lights in a stable unified titlebar; they no longer live inside scrolling SwiftUI content.
  • Enable immediate background dragging through isMovableByWindowBackground.
  • Use an opaque semantic window background and zero window-content corner clipping to remove the black panel edge while keeping normal system shadow/rounding.
  • Keep the titlebar height stable before applying the content size, preventing layout jumps.
  • Update the sidebar selection immediately, defer heavy detail construction by one display frame, cancel stale category work, and disable transition animation for the detail swap.
  • Cache category refreshes for short repeat visits and move sound-pack discovery off the click path. Statistics retains its @StateObject model instead of rebuilding it on every switch.
  • Add UI/unit coverage for native window capabilities, reuse, category switching, refresh caching, and sidebar accessibility.

2. Shared native shell, theme-specific Settings content

The window shell is common to every theme: titlebar, traffic lights, dragging, resizing, full screen, shadows, and safe content placement stay in AppKit.

Inside that shell:

  • PingIsland native (default) keeps the original colored icon tiles, two-line labels, rounded glass cards, category colors, and existing product character.
  • macOS aligns with Polish Settings window chrome and category responsiveness #285: compact source-list rows, outline SF Symbols, single-line labels, system accent selection, sidebar material, and macOS control geometry.
  • Pixel uses code-rendered pixel glyphs, Silkscreen type, one-pixel corners, grid surfaces, and two persisted classic palettes.

The icon model deliberately keeps PingIsland's original filled symbols separate from the macOS outline symbols so one theme can no longer silently overwrite another.

Pixel texture is now composed inside each surface background rather than above the Settings hierarchy. Cards and controls therefore remain visually above the grid. The same correction is applied to the notch and detached Island surfaces so the layering contract is consistent across presentations.

Game Boy Olive keeps its deep handheld-green surfaces and classic yellow-green accent, while primary and secondary foregrounds use accessibility-adjusted light tones. This preserves the palette identity while restoring readable contrast and clear surface/content hierarchy.

3. Experience theme architecture

  • Add a compiled-in IslandExperienceTheme contract covering Visual, Interaction, Motion, lifecycle Sound, and auxiliary Sound tokens.
  • Resolve themes in ExperienceThemeRegistry and inject the active definition through the SwiftUI environment.
  • Keep standard as the persisted compatibility identifier and make PingIsland native the fresh-install/invalid-value fallback.
  • Persist the Pixel palette independently so Arcade Neon and Game Boy Olive share components, motion, and game-style audio without duplicating a theme family.
  • Keep local CESP/OpenPeon packs as audio-only overrides rather than runtime UI bundles.

4. Semantic feedback and clearer confirmation actions

  • Route product events through AppSoundFeedbackEvent; feature code names what happened instead of selecting a filename.
  • Extend feedback to launch, detach, new session, allow, scoped allow, deny, idle reminder, rapid submit, usage warning, and usage recovery while preserving the five configurable lifecycle moments.
  • PingIsland native: original PingIsland 8-bit sound language, extended to the new moments.
  • macOS: macOS system-sound mappings.
  • Pixel: AgentIsland game-style mappings, shared by both Pixel palettes.
  • Centralize confirmation roles: allow is green, scoped/session allow is blue, deny is red, and neutral remains gray. Every role also keeps a label, icon, accessibility hint, and reduced-motion-safe press state so color is not the only signal.

5. Documentation and extension boundary

  • Rename the Sound sidebar subtitle to Themes and sounds (主题与提示音).
  • Document the built-in families, semantic sound flow, Settings shell ownership, source layout, persistence contract, first-party theme checklist, Pixel colorway path, texture-layering rule, tests, and the distinction between experience themes and CESP packs.
  • Keep each built-in theme in its own implementation file, with shared semantic components and symbol rendering separated from theme definitions.

See docs/experience-themes.md for the contributor guide.

Visual verification

These screenshots were rendered from the final Settings implementation in an AppKit-hosted Xcode test window and exported from the passing .xcresult. The two Pixel renders were refreshed after moving the grid below content; Game Boy Olive also includes the contrast-adjusted foreground palette.

PingIsland native macOS / #285-aligned
PingIsland native Settings macOS Settings
Pixel — Arcade Neon Pixel — Game Boy Olive
Pixel Arcade Neon Settings Pixel Game Boy Olive Settings

Verification

  • git diff --check is clean.
  • swiftc -parse passed for all changed app sources.
  • Both localization catalogs pass plutil -lint and contain matching keys.
  • Local focused Prototype regression suite: 129 tests passed (excluding the e2e/socket suites, matching the CI validation scope).
  • GitHub full validation + Universal package run: Prototype tests, complete PingIslandTests, Release app build, ad-hoc signing, DMG, and ZIP all passed. Packaging explicitly builds arm64 x86_64 with macOS 14.0 as the deployment target.
  • GitHub final Pixel layering and rendered screenshot validation: Prototype tests, complete Xcode unit tests, four AppKit-hosted theme renders, .xcresult export, and screenshot upload all passed.

Test package

Download the Universal unsigned DMG + ZIP artifact from the successful GitHub run:

The artifact is ad-hoc signed and intended for local testing. On first launch, macOS may require right-click → Open. It contains both Intel (x86_64) and Apple Silicon (arm64) slices.

@Yankj Yankj changed the title Add experience themes and semantic action feedback Add PingIsland, macOS, and Pixel experience themes Aug 26, 2026
@erha19

erha19 commented Aug 27, 2026

Copy link
Copy Markdown
Owner

@Yankj 提供一些视觉效果截图?不然无法判断

@Yankj Yankj changed the title Add PingIsland, macOS, and Pixel experience themes Build experience themes and overhaul Settings window UX Aug 27, 2026
@Yankj

Yankj commented Aug 28, 2026

Copy link
Copy Markdown
Author

@erha19 补充了哈。
1、优化了设置的拖拽反馈,之前总是有点慢
2、改了在主题的定义(UI + 声音),开放主题
3、在原风格基础上,自带增加了2套主题(MacOS风格、像素风)

@erha19

erha19 commented Aug 31, 2026

Copy link
Copy Markdown
Owner

@Yankj 非常感谢你的提交,当前还存在部分冲突麻烦解决一下,同时针对你的提交,合并后我会进行一轮视觉优化后再进行版本发布 ~

@Yankj

Yankj commented Aug 31, 2026

Copy link
Copy Markdown
Author

@erha19 感谢提醒,冲突已经解决并推送。

这次将 PR 分支同步到了最新 main(包含 v0.28.3 以及近期会话并发、完成事件去重、Claude 会话标题等改动)。冲突主要集中在提示音状态跟踪:上游已经把 docked / detached 两套视图中的状态比较收敛为由 SessionMonitor 持有的单一 SessionSoundEdgeTracker。合并时我保留了这一集中式实现,并将本 PR 的语义化主题声音接入同一个入口:

  • 保留上游按 session 状态边缘去重的逻辑,避免列表抖动、窗口形态切换或完成事件重放导致重复提示音;
  • 将主题化生命周期声音以及新会话、快速提交、等待提醒和用量提醒统一交给 AppSoundFeedbackEvent
  • 移除 NotchViewDetachedIslandWindowController 中重复的本地声音 tracker,同时保留主题视觉、动效和 Reduced Motion 改动;
  • 补充合并后新增测试所需的 MainActor 隔离标注。

验证结果:

  • 本地 Prototype 回归:129 tests passed;
  • GitHub macOS 15 / Xcode 16.4 完整验证:Prototype、完整 PingIslandTests、主题截图渲染及导出均通过;
  • GitHub 当前已将 PR 标记为 MERGEABLE

也感谢后续继续帮忙做视觉优化~

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