# Settings Screen Design — Reference

## Three-Column Layout Pattern

### Files
- `SettingsScreen.kt` — main screen composable
- `SettingsDesignSystem.kt` — components (in `screens/settings/` package)
- Per sub-screen: `PlaybackSettingsScreen.kt`, `DebridServicesScreen.kt`, `TraktServicesScreen.kt`, `SubtitleStyleSettingsScreen.kt`, `AddonsScreen.kt`

### Layout hierarchy
```
UnifiedChromeScaffold
  └── SettingsGradientBackground (fillMaxSize, radial gradient)
      └── Row (fillMaxSize, spacedBy 48dp)
          ├── LazyColumn (220dp width, fillMaxHeight) — category rail
          │   └── SettingsRailItem × N
          └── Box (weight=1f, fillMaxHeight) — content panel
              └── SettingsCategoryContent (verticalScroll Column)
                  ├── Text("Settings", 40sp Bold)
                  ├── Text(category.label, 17sp, alpha 0.6f)
                  └── when(category) → sub-screen composable
```

### Focus routing (Rail ↔ Detail)

| Direction | Source | Target | Mechanism |
|-----------|--------|--------|-----------|
| Right | Rail item | Content panel 1st item | `onPreviewKeyEvent(DirectionRight) → onMoveToDetail()` |
| Left | Content panel | Rail selected item | `onPreviewKeyEvent(DirectionLeft) → onMoveToRail()` |

**Key detail:** The content panel `Box` must have `onPreviewKeyEvent` with LEFT handler. The rail `LazyColumn` must have `onPreviewKeyEvent` with RIGHT handler. Both must return `true` when consuming to prevent dual-focus split bug.

### Focus zone tracking
```kotlin
// In your focus controller:
fun enterSettingsCategory()  // zone = SettingsCategory
fun enterSettingsDetail()     // zone = SettingsDetail
fun recordSettingsCategory(cat: String)  // helps on back-navigation

// Back key in handleBack():
state.activeZone == TvFocusZone.SettingsDetail → enterSettingsCategory(); return true
```

### FocusRequester maps
```kotlin
val railFocusRequesters = remember { categories.associateWith { FocusRequester() } }
val contentFocusRequesters = remember { SettingsPanel.entries.associateWith { FocusRequester() } }
```
Stable `remember {}` — no key args — prevents recreation on every recomposition.

## Design System Components (new)

All in `ui/screens/settings/SettingsDesignSystem.kt` (appended after line 773):

### SettingsGradientBackground
```kotlin
Box(fillMaxSize) {
    background(
        Brush.radialGradient(
            radius = 1800f,
            center = Offset(800f, -400f),
            colors = listOf(
                Color(0xFF8B1A1A),    // crimson center
                Color(0xFF0A1628),    // navy mid
                Color(0xFF0D1B2A),    // dark blue edge
            ),
        )
    )
    content()
}
```

### SettingsRailItem
- Transparent `Card` (no bg on focus either)
- Text: 17sp, weight by state (SemiBold when selected/focused)
- Color: red (`0xFFE50914`) when selected, White when focused (not selected), alpha 0.7f otherwise
- Min height: 52dp
- `onFocused` callback on focus change (for category auto-selection)

### SettingsContentToggleRow
- Card: transparent bg → White on focus
- Text: White → dark (`0xFF1A1A2E`) on focus
- Icon tint: alpha 0.7f → dark on focus
- Border: only on focus, 1dp white alpha 0.3f
- Shape: RoundedCornerShape(32dp)
- Toggle: `SettingsTogglePill(checked)` inline

### SettingsContentActionRow
- Same focus behavior as toggle row
- Adds `value` text + `ChevronRight` trailing icon
- Value and chevron fade to dark on focus

### SettingsTogglePill (private, new)
```kotlin
Box(width=44.dp, height=26.dp, clip=CircleShape)
    .background(if checked → red 0xFFE50914 else → White alpha 0.2f)
    .padding(2.dp)
    -> Box(size=22.dp, clip=CircleShape).background(White)
```
Position: CenterEnd when ON, CenterStart when OFF.

## Dual DesignSystem File Risk

Two files with overlapping component names:

| Component | `screen/settings/SettingsDesignSystem.kt` | `ui/components/SettingsDesignSystem.kt` |
|-----------|-------------------------------------------|----------------------------------------|
| Toggle pill | 44×26dp, red | 46×24dp, accent color (via `TogglePill` private) |
| Toggle row | `SettingsContentToggleRow` | `SettingsToggleRow` |
| Action row | `SettingsContentActionRow` | `SettingsActionRow` |
| Rail item | `SettingsRailItem` (text-only, no border) | `SettingsRailButton` (card-based with icon) |
| Group card | — (not needed in new design) | `SettingsGroupCard` |

**Impact:** Sub-screens embedded in the new gradient container use old card components. The visual clash is stark — dark rectangles on the gradient background.

**Remediation:** Give each sub-screen `embedded: Boolean`. When `true`:
- Replace `SettingsGroupCard` wrappers with direct content
- Replace `SettingsActionRow` / `SettingsToggleRow` with `SettingsContentActionRow` / `SettingsContentToggleRow`
- Drop explicit background colors (`NuvioTheme.colors.Background`, `NuvioTheme.colors.SurfaceCard`)
- Use transparent container with white pill focus (inherited from parent gradient)

## Dead-End Prevention (SOURCE_PREFS)

The `SOURCE_PREFS` panel exists in the enum and is listed under `PLAYBACK.panels` but has no `when` branch in `SettingsCategoryContent`. Pressing RIGHT on "Source Preferences" reaches a focusable content element that renders nothing.

**Fix:** Either add a rendering branch for the panel, or remove it from the category's `panels` list.

## Gradient Performance Notes

- `Brush.radialGradient` at 1920×1080: generally fine on modern TV GPUs (Mali-G52+, Adreno 610+)
- On low-end (Mali-400, older Adreno): potential shader compilation jank on first render (1-3 frames)
- Optimization option: pre-render to `ImageBitmap` via `drawIntoCanvas` in a `LaunchedEffect`, cache with `remember`
- No overdraw concerns — TV renders a single full-screen layer

## Screenshot Match (Netflix-style)

| Element | Screenshot | Implementation |
|---------|-----------|----------------|
| Left icon rail | 4 icons, gear selected (red bg) | Not in SettingsScreen — uses `UnifiedChromeScaffold` sidebar |
| Category rail | Text list, "Playback" in red | `SettingsCategoryList` + `SettingsRailItem` |
| Content area | White header "Settings" | 40sp Bold header |
| Sub-header | "Playback" in smaller white | 17sp, alpha 0.6f |
| Auto-play row | Toggle + icon in white pill on focus | `SettingsContentToggleRow` |
| Casting row | White pill chevron on focus | `SettingsContentActionRow` |
| Red toggle | White circle on red bg, 44×26 | `SettingsTogglePill` (red 0xFFE50914) |
| Speed row | Value "Normal" + chevron | `SettingsContentActionRow` with value |

## Build Verification

After settings screen changes, build with:
```bash
cd ~/Unspooled && ./gradlew :app:assembleDebug
```
Watch for: import resolution ambiguity (dual `SettingsDesignSystem`), missing when branches, unused import warnings on gradient/transparent constants.**Reference file for skill `tv-app-build`. Contains session-specific detail on settings screen patterns, component design, and audit findings.**
