Commit Graph
2 Commits
Author SHA1 Message Date
enricobuehlerandClaude Opus 5 0a32f4eab1 fix(client/apple): the iOS slice hit the type-checker wall, and tvOS couldn't be checked at all
`ContentView.body` grew two modifiers and stopped type-checking on the iOS slice —
"unable to type-check this expression in reasonable time", a failure macOS builds
never show and the one Apple CI never builds. Split into the screen plus its
lifecycle drivers, then the prompt chain, with each alert's presentation Binding
lifted out the way the deep-link one already was.

tvOS couldn't be checked from the command line at all: HomeView imports the slide
transition, which ships with the Xcode project only because its manifest breaks
SwiftPM's whole-graph validation. `canImport` instead of a bare `os(tvOS)` gate
makes the tvOS sources compile without it, and the app still gets the transition
because there the module is present. Both slices now typecheck by hand.

The scope switcher is tvOS-gated with them: a name prompt and a nested management
menu are not what a remote does well, and §5.4 keeps profile EDITING off
controller-first surfaces in v1 — they honor bindings and render pinned cards.

Also: release the session's settings latch when a connect fails, is refused, or is
abandoned mid-handshake. Only `disconnect` cleared it, so a failed dial left the
would-be session's resolution latched over the globals.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 12:06:41 +02:00
enricobuehlerandClaude Opus 5 3ae9b83290 feat(client/apple): the settings screen edits profiles, and says which rows it changed
One settings surface, two layers. A scope switcher at the top of the Mac window and
the iOS sidebar swaps the whole screen between Default settings and one profile's
overrides; the section builders stay the single definition of every row and just
change which layer their binding reads and writes (design §5.1). A parallel profile
editor would have drifted from this one field by field, and the revamp's captions
and curation would have had to be written twice.

`SettingsFields` is where a row's three faces meet — the UserDefaults key its global
lives under, the overlay slot an override lives in, and the name a reset carries.
Keeping them in one place is what stops a row from writing an override the reset
button can't find.

Every row shows the EFFECTIVE value, so an untouched row reads as the live global.
Touching a control records the override — always, even when the new value equals
today's global, because that is a pin and the profile must keep it when the global
later moves. Nothing is inferred by diffing at save time.

Overridden rows say so (accent dot + "Overrides Default settings") and carry the
only way back: an explicit Reset. That pair is not garnish. The model deliberately
never infers "not overridden" from a value comparison, so without a reset affordance
a profile is a one-way door.

Tier-G and tier-H rows don't render in profile scope at all — this device's speaker,
microphone and channel, its pointer capture and haptics, the HUD corner, the library
switch, the gamepad-UI switch, which physical pad is forwarded, and auto-wake, which
is about a host and a network rather than about Game vs Work. Sections that would be
left empty (Session off macOS, Library) collapse instead of rendering a bare group.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 12:06:41 +02:00