# NuvioTV-sidebar Navigation Patterns

## Tricky D-Pad Flow

### 1. Sidebar items cut off
**Fix**: Use `Column(Modifier.weight(1f, fill=false).verticalScroll(scrollState))` instead of a bare Column. Sidebar height fills parent; items are scrollable when they overflow.

### 2. Can't move right from middle sidebar position
**Root cause**: Per-item `onPreviewKeyEvent` only handles collapse at the top item.
**Fix**: Move DirectionRight/DirectionLeft handler to the **container** Column's `onPreviewKeyEvent`, not individual items:
```kotlin
Column(modifier = Modifier
    .onPreviewKeyEvent { event ->
        if (event.type == KeyEventType.KeyUp) {
            when (event.key) {
                Key.DirectionRight -> {
                    if (isExpanded) {
                        onExpandedChange(false)
                        onNavigateToContent?.invoke()
                        true
                    } else false
                }
                else -> false
            }
        } else false
    }
)
```

### 3. Banner cut off by sidebar
**Root cause**: Content Box uses `Modifier.fillMaxSize()` — doesn't account for sidebar width.
**Fix**: `Modifier.weight(1f).fillMaxHeight()` on the content Box:
```kotlin
Row(Modifier.fillMaxSize()) {
    NexSidebar(...)   // fixed width
    Box(
        Modifier.weight(1f).fillMaxHeight()  // ← weight(1f) not fillMaxSize()
    ) { ... }
}
```

### 4. Banner focus auto-opens sidebar
**Root cause**: Sidebar's `onFocusChanged { onExpandedChange(it.hasFocus) }` fires incorrectly.
**Fix**: Gate sidebar expansion with a `contentHasFocus` boolean:
```kotlin
var contentHasFocus by remember { mutableStateOf(true) }
// On content Box:
.onFocusChanged { f -> contentHasFocus = f.isFocused }
// On sidebar:
onExpandedChange = { if (contentHasFocus) sidebarExpanded = it }
```

### 5. Choppy sidebar animation
Use `animateDpAsState(tween(280))` for width, `animateFloatAsState(tween(200))` for label alpha. Use `animateColorAsState(tween(180))` for item backgrounds. Not `animateTo()` in coroutines.

### 6. Focus transfer timing
Don't call `requestFocus()` directly in key event handlers. Wrap in coroutine with delay:
```kotlin
scope.launch {
    delay(50)
    try { someFocusRequester.requestFocus() } catch (_: Exception) {}
}
```
Or for frame-precise timing (NuvioTV pattern):
```kotlin
repeat(2) { withFrameNanos {} }
drawerItemFocusRequesters[route].requestFocus()
```
