Skip to content

Add compact named external-display controls in Tools - #209

Closed
Blazetes wants to merge 5 commits into
didriksg:mainfrom
Blazetes:feature/batch-display-connections
Closed

Blazetes wants to merge 5 commits into
didriksg:mainfrom
Blazetes:feature/batch-display-connections

Conversation

@Blazetes

@Blazetes Blazetes commented Oct 7, 2026 •

Copy link
Copy Markdown

What & why

Manage physical external displays from one compact item in Tools, between Auto-Disconnect Built-in and Virtual Displays. The item has a native master switch and display names underneath: 1-4 names occupy one row, 5-8 occupy two rows, with four columns rather than a device-count cap. Connected names use the normal foreground; held-disconnected names are gray. Each name can be toggled individually, and tooltips preserve long names.

The master switch is on when any controllable external display is connected. Turning it off disconnects externals only. In a mixed setup, the same-row reconnect button restores all available held externals without adding permanent duplicate action rows. The menu icon is two equal 16:9 screens arranged diagonally, as a transparent monochrome template SVG; the application icon is unchanged.

Batch operations never target the built-in for disconnection. If it was intentionally disconnected, restore it before the external shutdown. If no usable built-in is available, retain a viewable physical keeper and label the item Other External Displays. Virtual or inactive screens cannot act as keepers, and unavailable unplugged records cannot be reconnected.

A shared transaction gate protects the last physical screen until the blocking operation truly finishes, including after a UI timeout. Queued disconnects pin their UUID and recheck safety after DDC drains. Late results retain recovery/input state, stop further batch changes and clear timeout messages only when the actual online list matches the requested state. Release and local dev deployment bundle the compiled vector asset catalog.

The physical-configuration safeguards are shared with #210. Both branches are independently buildable; after either merges, the other can be rebased to remove those shared backend portions.

How tested

  • Exact source d7137e289676e48ebc9891ce0d1458942ad30b1b passed local make check: strict SwiftLint, unit tests, x86_64 typecheck and all 283 extracted localization keys.
  • Chinese translation completeness and full local ./scripts/release.sh v0.0.0-ci passed with Xcode 27.0 (27A266a) / SDK 27.0. App and CLI are universal; deep signature and DMG integrity checks passed.
  • Planner/state/gate regression tests cover external-only plans, laptop/desktop/mirror keepers, no-viewable-keeper safety, unavailable/duplicate/mixed states, four-column layout, UUID ordering and overlapping/timed-out requests.
  • Production batch service/view fixtures passed simulated operation and settled-timeout assertions plus 33 language/state previews. The packaged application's own SVG resolves and renders transparently at 16/20/24/32px.
  • Live multi-monitor switching, clamshell/sleep recovery and installed-app interaction: not run.

Checklist

  • Builds locally (./scripts/release.sh v0.0.0-ci, exact source above)
  • Added/updated Crisp/Resources/Localizable.xcstrings
  • Screenshot or short clip for UI change

Native SwiftUI fixtures with mocked display services, not live-monitor screenshots:

Four external displays Eight external displays
Four external names Eight external names
Mixed state Protected desktop keeper
Mixed connection state Protected viewable keeper

@Blazetes Blazetes changed the title Add batch display connection controls in Tools Add compact named external-display controls in Tools Oct 7, 2026
@didriksg

Copy link
Copy Markdown
Owner

I'm going to pass on the batch switch. One click that turns off every external screen is more than I want behind a single control, and with #218 each display gets its own switch, so two displays are two clicks. The backend is the same as in #210, and my reply there covers it. Reading it also showed me a few timeout cases in the disconnect path that I'm looking at separately.

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