Skip to content

Move the settings into UIFoundation's Settings window - #41

Merged
Mx-Iris merged 5 commits into
mainfrom
feat/settings-window
Oct 11, 2026
Merged

Mx-Iris merged 5 commits into
mainfrom
feat/settings-window

Conversation

@Mx-Iris

@Mx-Iris Mx-Iris commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

The Preferences window and the separate Private Discriminator Settings window are now two pages — General and Private Discriminator — of one Settings window built on UIFoundation's SettingsWindowController (the package's Settings trait, product UIFoundationSettingsUI). The pages are laid out the way RuntimeViewer lays out its settings in the same window.

Only the presentation changes. Every value stays where it was: PreferenceManager keeps the general settings in the standard user defaults under the same keys, and PrivateDiscriminatorStore keeps its own in config.json, so existing users keep their settings and nothing is migrated.

What changes for users

  • The app menu's Preferences… item is now Settings… (still ⌘,). The Private Discriminator Settings… item is gone; its content is the Private Discriminator page.
  • The window has a sidebar of pages with plain glyphs, back and forward buttons, and grouped forms. It remembers where it was left and reopens on the last page.
  • Each group has a header, and what a setting does is written under its group.
  • Appearance is picked from the three pictures System Settings shows for the same choice. They are read from the system at run time, so the app ships no copy of them; on a macOS that has moved them, the page falls back to the pop-up menu.
  • The timeouts are a field with a stepper.
  • The General page follows PreferenceManager by KVO, so a change made elsewhere — the Dashboard's color format switch — shows up while the window is open.
  • Reset (⌘⇧⌫) is a Reset Settings row at the end of the General page, laid out the way Xcode's settings lay out theirs.
  • On the Private Discriminator page, the default library row names the modules it downloads and shows how the last update went.

Implementation notes

  • LookInside.xcodeproj: the UIFoundation reference enables the Settings trait next to AppleInternal, the app target links UIFoundationSettingsUI, and the target's membership list swaps the three removed files for the three new ones in LookInside/Settings/.
  • PreferenceValuePolicy (LookInsideHostCore) now holds the timeout and contrast rules the old form kept as private helpers, with swift-testing cases.
  • NavigationManager keeps one SettingsWindowController for the app's lifetime. The sidebar is 20 points wider than UIFoundation's default so "Private Discriminator" fits, and the window grows by as much, so the pages keep their width.
  • The appearance pictures are AppearanceAuto, AppearanceLight and AppearanceDark in /System/Library/ExtensionKit/Extensions/Appearance.appex.
  • Rows that hold a button are an HStack rather than LabeledContent, which would line the button up with the title instead of centering it on both lines.
  • PrivateDiscriminatorStore exposes defaultLibraryModuleNames; the page formats them as a list for the user's language.
  • The DEBUG UI snapshots capture the new window as the settings scene (previously preferences), so its baseline needs recording again.
  • String catalog: Settings, Settings…, General, the group headers Hierarchy, Timeouts and Modules, the thumbnail captions System, Light and Dark, and Reset Settings with its description, all in 13 languages. The five strings no code uses any more are marked stale, and the empty key left by the old Preferences view's Stepper("") is removed.

After pulling

Turning a package trait on is not something Xcode's incremental build description notices. If a build reports cannot find 'SettingsWindowController' in scope, delete the project's DerivedData and build again.

Testing

  • swift test in Packages/LookInsideHostCore: all 117 tests pass, including the new PreferenceValuePolicyTests.
  • xcodebuild Debug build of the LookInside scheme succeeds, rerun after each layout commit; no new warnings.
  • Release build compiles and links the app (last run with the RuntimeViewer layout; the later commits change no DEBUG-only code). It was run without the sibling LookInside-Injector and LookInside-MCP checkouts, so the two embed phases stopped it afterwards, as they are designed to.
  • A small probe loaded the three appearance pictures on macOS 27.2 the way the page does. Earlier macOS versions are untested; where the pictures are missing, the page shows the menu instead.
  • The layout was settled by looking at the window on screen; the later commits are the result.

The Preferences form clamped a typed timeout to 0.1-120 s (falling back
to the default for anything that is not a positive, finite number) and
kept the image contrast level between 0 and 2, in private helpers of its
view model that no test reached. PreferenceValuePolicy holds both rules
now, so the Settings window can use them and swift test covers their
edges.
The Preferences window and the separate Private Discriminator Settings
window become two pages, General and Private Discriminator, of one
Settings window: UIFoundation's SettingsWindowController, from the
package's Settings trait (product UIFoundationSettingsUI).

Only the presentation changes. PreferenceManager still keeps the general
settings in the standard user defaults under the same keys, and
PrivateDiscriminatorStore still keeps its own in config.json.

- App menu: "Preferences…" is now "Settings…" (still Command-comma); the
  "Private Discriminator Settings…" item is gone.
- The General page writes through PreferenceManager and follows it by
  KVO, so a change made elsewhere, such as the Dashboard's color format
  switch, shows up while the window is open. Typed timeouts and the
  contrast level go through PreferenceValuePolicy.
- NavigationManager keeps one window controller for the app's lifetime,
  so the window reopens on the last page; with two pages the back and
  forward controls are hidden.
- The DEBUG UI snapshots capture the new window as the "settings" scene.
- The app target's membership list swaps the three removed files for the
  three new ones in LookInside/Settings.
- String catalog: "Settings", "Settings…" and "General" in all 13
  languages; the five strings no code uses any more are marked stale.
Copilot AI balanced review requested due to automatic review settings October 11, 2026 03:05

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

RuntimeViewer is the reference for UIFoundation's Settings window, and
both pages now follow it:

- The sidebar shows plain glyphs at 15 points. It is 20 points wider
  than UIFoundation's default so "Private Discriminator" fits, and the
  window grows by as much, so the pages keep their width.
- The back and forward controls are shown again.
- Each group has a header, and what a setting does moves from a line
  under the row to the group's footer.
- Appearance is chosen from three thumbnails, read at run time from
  System Settings' Appearance extension, so LookInside ships no copy of
  them. Should a macOS version move them, the page falls back to the
  pop-up menu.
- The timeouts are a field with a stepper; the footer gives the unit.

The new headers and thumbnail titles are translated into all 13
languages. The empty key leaves the string catalog: the Stepper("") in
the old Preferences view was the last thing that used it.
A group holding nothing but a button read as an empty box. The reset is
now laid out the way Xcode's settings lay out theirs: a "Reset" header
over a row titled "Reset Settings", with what it does under the title
and the button at the trailing edge. The default library row names the
modules it downloads, shows how the last update went under them, and
keeps its button at the trailing edge.

The module names come from the store, which now exposes them, and are
formatted as a list for the user's language. The two new strings are
translated into all 13 languages.
LabeledContent lines its control up with the first line of its label,
so the Reset button sat level with "Reset Settings" instead of in the
middle of the row, and the default library's button did the same once
its status showed. Both rows are now an HStack, the way RuntimeViewer
lays out its own, with the line under the title styled as before.
@Mx-Iris
Mx-Iris merged commit c4e3c53 into main Oct 11, 2026
2 checks passed
@Mx-Iris
Mx-Iris deleted the feat/settings-window branch October 11, 2026 13:52
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