# TV Settings Two-Pane Focus Pattern (NuvioTV)

## The Problem

A `.focusable()` wrapper Box in a two-pane layout **traps D-Pad events**. When the user presses RIGHT from the rail, focus lands on the wrapper Box. Pressing DOWN/UP stays stuck on the wrapper — it never reaches the child controls (SettingsActionRow, SettingsChoiceChip, text fields).

## The Fix (NuvioTV Architecture)

### 1. REMOVE the `.focusable()` wrapper

```kotlin
// BEFORE (BROKEN — traps focus)
Box(
    modifier = Modifier
        .focusRequester(detailFocusRequester)
        .focusable() // ← THIS IS THE BUG
) {
    when (selected) { ... }
}

// AFTER (working)
Box(
    modifier = Modifier
        .onKeyEvent { /* LEFT key → back to rail */ }
        .onFocusChanged { /* bounce-back guard */ }
) {
    when (selected) { ... }
}
```

### 2. Per-panel FocusRequesters

Each settings panel gets its own `FocusRequester` in a map:

```kotlin
val contentFocusRequesters = remember {
    panels.associateWith { FocusRequester() }
}
```

Pass it to sub-screens:

```kotlin
SettingsPanel.DEBRID -> DebridServicesScreen(
    contentFocusRequester = contentFocusRequesters[SettingsPanel.DEBRID],
)
```

### 3. NuvioTV fallback pattern

```kotlin
LaunchedEffect(pendingContentFocusRequestId) {
    if (!allowDetailFocus) return@LaunchedEffect
    delay(120) // SETTINGS_DETAIL_FOCUS_DELAY_MS
    val requester = contentFocusRequesters[selected]
    val requested = if (requester != null) {
        runCatching { requester.requestFocus() }.isSuccess
    } else false
    // FALLBACK: if FocusRequester misses, brute-force move right
    if (!requested) {
        focusManager.moveFocus(FocusDirection.Right)
    }
}
```

### 4. Bounce-back guard

Prevents accidental focus on detail pane without RIGHT key intent:

```kotlin
.onFocusChanged { state ->
    if (state.hasFocus && !allowDetailFocus) {
        runCatching { railFocusRequesters[selected]?.requestFocus() }
    }
}
```

### 5. LEFT key returns to rail (not PreviewKeyEvent)

Use `onKeyEvent` on the detail pane (consumed after children):

```kotlin
.onKeyEvent { event ->
    if (event.type == KeyEventType.KeyDown && event.key == Key.DirectionLeft) {
        allowDetailFocus = false
        runCatching { railFocusRequesters[selected]?.requestFocus() }
        true
    } else false
}
```

### 6. Sub-screen FocusRequester wiring

Each sub-screen accepts `contentFocusRequester: FocusRequester? = null`:

```kotlin
@Composable
fun PlaybackSettingsScreen(
    contentFocusRequester: FocusRequester? = null,
    ...
) {
    // Attach to first focusable element
    SettingsChoiceChip(
        modifier = if (contentFocusRequester != null) {
            Modifier.fillMaxWidth().focusRequester(contentFocusRequester)
        } else Modifier.fillMaxWidth(),
        ...
    )
}
```

For `forEach` loops, use `forEachIndexed`:

```kotlin
list.forEachIndexed { index, item ->
    SettingsChoiceChip(
        modifier = if (index == 0 && contentFocusRequester != null) {
            Modifier.fillMaxWidth().focusRequester(contentFocusRequester)
        } else Modifier.fillMaxWidth(),
        ...
    )
}
```

## Required Imports

```kotlin
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.input.key.onKeyEvent
```

## Key Constants

```kotlin
private const val SETTINGS_DETAIL_FOCUS_DELAY_MS = 120L
```

## State Variables

```kotlin
var selected by remember { mutableStateOf(defaultPanel) }
var allowDetailFocus by remember { mutableStateOf(false) }
var pendingContentFocusRequestId by remember { mutableLongStateOf(0L) }

val railFocusRequesters = remember { panels.associateWith { FocusRequester() } }
val contentFocusRequesters = remember { panels.associateWith { FocusRequester() } }
```

## Files Affected

- `app/src/main/java/com/nexstream/app/ui/screens/settings/SettingsScreen.kt`
- All sub-screens in `app/src/main/java/com/nexstream/app/ui/screens/settings/`
