# CircularRailNavigation for NexStream

Curved, animated left-side navigation rail — feature-flagged alternative to NexSidebar.

## Files
- `app/src/main/java/com/nexstream/app/ui/components/CircularRailNavigation.kt` — Main component + `CurvedRailShape`
- `app/src/main/java/com/nexstream/app/ui/components/NavigationRailWrapper.kt` — Conditional renderer (Classic vs Circular)
- `app/src/main/java/com/nexstream/app/ui/components/CircularNavItem.kt` — Data class for nav items
- `app/src/main/java/com/nexstream/app/domain/model/NavigationStyle.kt` — Enum: `CLASSIC`, `CIRCULAR_EXPERIMENTAL`
- `app/src/main/java/com/nexstream/app/data/local/PreferencesManager.kt` — `navigationStyle` Flow + setter
- `app/src/main/java/com/nexstream/app/ui/screens/settings/NavigationStyleSettingsScreen.kt` — Settings UI
- `app/src/main/java/com/nexstream/app/ui/navigation/Screen.kt` — `NavigationStyleSettings` route
- `app/src/main/java/com/nexstream/app/ui/navigation/NexStreamNavHost.kt` — NavHost route
- `app/src/main/java/com/nexstream/app/ui/screens/settings/SettingsScreen.kt` — "Navigation" section
- `app/src/main/java/com/nexstream/app/ui/screens/settings/SettingsViewModel.kt` — `navigationStyle` in UI state + setter

## How It Works
- `CurvedRailShape` uses `Shape.createOutline()` with `cubicTo()` bezier for curved left edge
- `NavigationRailWrapper` reads `navigationStyle` from `SettingsViewModel`, renders `CircularRailNavigation` or `NexSidebar`
- Auto-collapse after 3s inactivity via `derivedStateOf` + `LaunchedEffect`
- Expand on Menu/Left key, collapse on Right/Back
- D-pad safe with `focusProperties` on every item
- Selected: scale (1.04x), glow, highlighted bg, persistent active state
- Icons collapsed, icons+labels expanded

## Integration Status
- ✅ `NetflixHomeScreen` — wired via `NavigationRailWrapper`
- ✅ `NetflixSearchScreen` — wired via `NavigationRailWrapper` (classic + circular with virtual keyboard)
- ✅ `CatalogBrowserScreen` — wired via `NavigationRailWrapper` (added `navController` param)
- ✅ `MoviesScreen` — wired via `CatalogBrowserScreen` → `NavigationRailWrapper`
- ✅ `TvShowsScreen` — wired via `CatalogBrowserScreen` → `NavigationRailWrapper`
- ✅ `MyListScreen` — wired via `CatalogBrowserScreen` → `NavigationRailWrapper`
- ✅ Settings toggle — fully functional
- ✅ Build — compiles and APK builds clean

## How NetflixSearchScreen Integration Works
The circular rail on the search screen coexists with the virtual keyboard. The rail is on the left (64dp), keyboard on the right. `contentHasFocus` prevents sidebar expansion when keyboard has focus. `onNavigateToContent` collapses sidebar and returns focus to keyboard via `FocusRequester`.

## How CatalogBrowserScreen Integration Works
Added `navController: NavController` parameter to `CatalogBrowserScreen`. All callers (MoviesScreen, TvShowsScreen, MyListScreen) pass their `navController`. The wrapper reads `navigationStyle` from `SettingsViewModel` and renders the appropriate rail.

## Pitfalls
- `Shape.createOutline()` signature: `(Size, LayoutDirection, Density) -> Outline` — NOT `(Size, LayoutDirection, PaddingValues)`
- Use `with(density) { curvatureDp.toPx() }` for dp→px conversion in Shape
- `LocalNavController` does NOT exist in this Compose Navigation version — pass `NavController` as parameter
- `sidebarNavigate` import: `com.nexstream.app.ui.components.netflix.sidebarNavigate`
- `NavigationRailWrapper` requires `navController` as explicit parameter (no default)
- Canvas composable (`androidx.compose.ui.graphics.Canvas`) is for bitmap drawing, NOT Compose layout — use Shape instead
- `Modifier.weight()` is internal in Compose TV — use `androidx.compose.foundation.layout.weight`
- **Dead code to remove**: `GlassDockSidebar.kt`, `TvDensityHelper.kt`, `FocusHelper.kt` — all defined but never imported/used
- **Settings screen**: Use `collectAsStateWithLifecycle()` NOT `collectAsState()`; use `LaunchedEffect` to sync `selectedIndex` from `uiState.navigationStyle` (String), NOT `toIntOrNull()`
- **Settings screen**: Each card needs its own `FocusRequester()`, NOT `FocusRequester.Default` shared across all cards
- **CircularRailNavigation**: Remove dead `isFocused` state from outer `forEachIndexed` loop — it's never read; use `item.route == selectedRoute` inline
- **CircularRailNavigation**: Remove `focusProperties` block — Compose handles vertical D-pad traversal in Columns automatically
- **Import cleanup**: Wildcard imports (`*`) are fine; only remove specific imports that are truly unused. Check non-import lines for actual usage.
