diff --git a/app/src/main/java/com/nuvio/tv/ui/components/CatalogRowSection.kt b/app/src/main/java/com/nuvio/tv/ui/components/CatalogRowSection.kt index 7646f7bb..63e0cb83 100644 --- a/app/src/main/java/com/nuvio/tv/ui/components/CatalogRowSection.kt +++ b/app/src/main/java/com/nuvio/tv/ui/components/CatalogRowSection.kt @@ -32,9 +32,19 @@ fun CatalogRowSection( catalogRow: CatalogRow, onItemClick: (String, String, String) -> Unit, onLoadMore: () -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + initialScrollIndex: Int = 0 ) { - val listState = rememberLazyListState() + val listState = rememberLazyListState( + initialFirstVisibleItemIndex = initialScrollIndex + ) + + // Restore scroll position if needed + LaunchedEffect(initialScrollIndex) { + if (initialScrollIndex > 0) { + listState.scrollToItem(initialScrollIndex) + } + } val shouldLoadMore by remember { derivedStateOf { diff --git a/app/src/main/java/com/nuvio/tv/ui/screens/home/HomeScreen.kt b/app/src/main/java/com/nuvio/tv/ui/screens/home/HomeScreen.kt index 15039c35..5b2976c5 100644 --- a/app/src/main/java/com/nuvio/tv/ui/screens/home/HomeScreen.kt +++ b/app/src/main/java/com/nuvio/tv/ui/screens/home/HomeScreen.kt @@ -9,6 +9,8 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment @@ -29,8 +31,35 @@ fun HomeScreen( onNavigateToDetail: (String, String, String) -> Unit ) { val uiState by viewModel.uiState.collectAsState() + val focusState by viewModel.focusState.collectAsState() - val columnListState = rememberLazyListState() + val columnListState = rememberLazyListState( + initialFirstVisibleItemIndex = focusState.verticalScrollIndex, + initialFirstVisibleItemScrollOffset = focusState.verticalScrollOffset + ) + + // Restore scroll position when state is available + LaunchedEffect(focusState.verticalScrollIndex, focusState.verticalScrollOffset) { + if (focusState.verticalScrollIndex > 0 || focusState.verticalScrollOffset > 0) { + columnListState.scrollToItem( + focusState.verticalScrollIndex, + focusState.verticalScrollOffset + ) + } + } + + // Save scroll position when leaving screen + DisposableEffect(Unit) { + onDispose { + viewModel.saveFocusState( + verticalScrollIndex = columnListState.firstVisibleItemIndex, + verticalScrollOffset = columnListState.firstVisibleItemScrollOffset, + focusedRowIndex = 0, // Basic implementation + focusedItemIndex = 0, // Basic implementation + catalogRowScrollStates = emptyMap() // Will be enhanced with horizontal scroll tracking + ) + } + } Box( modifier = Modifier @@ -79,6 +108,7 @@ fun HomeScreen( items = uiState.catalogRows, key = { _, item -> "${item.addonId}_${item.type}_${item.catalogId}" } ) { index, catalogRow -> + val catalogKey = "${catalogRow.addonId}_${catalogRow.type.toApiString()}_${catalogRow.catalogId}" CatalogRowSection( catalogRow = catalogRow, onItemClick = { id, type, addonBaseUrl -> @@ -92,7 +122,8 @@ fun HomeScreen( type = catalogRow.type.toApiString() ) ) - } + }, + initialScrollIndex = focusState.catalogRowScrollStates[catalogKey] ?: 0 ) } } diff --git a/app/src/main/java/com/nuvio/tv/ui/screens/home/HomeScreenFocusState.kt b/app/src/main/java/com/nuvio/tv/ui/screens/home/HomeScreenFocusState.kt new file mode 100644 index 00000000..897898b3 --- /dev/null +++ b/app/src/main/java/com/nuvio/tv/ui/screens/home/HomeScreenFocusState.kt @@ -0,0 +1,33 @@ +package com.nuvio.tv.ui.screens.home + +/** + * Stores focus and scroll state for the HomeScreen to enable proper state restoration + * when navigating back from detail screens. + */ +data class HomeScreenFocusState( + /** + * The index of the first visible item in the main vertical LazyColumn. + */ + val verticalScrollIndex: Int = 0, + + /** + * The pixel offset of the first visible item in the vertical scroll. + */ + val verticalScrollOffset: Int = 0, + + /** + * Index of the catalog row that had focus when navigating away. + */ + val focusedRowIndex: Int = 0, + + /** + * Index of the item within the focused catalog row. + */ + val focusedItemIndex: Int = 0, + + /** + * Map of catalog row keys to their horizontal scroll positions. + * Key format: "${addonId}_${type}_${catalogId}" + */ + val catalogRowScrollStates: Map = emptyMap() +) diff --git a/app/src/main/java/com/nuvio/tv/ui/screens/home/HomeViewModel.kt b/app/src/main/java/com/nuvio/tv/ui/screens/home/HomeViewModel.kt index b04e2af6..566eaf0f 100644 --- a/app/src/main/java/com/nuvio/tv/ui/screens/home/HomeViewModel.kt +++ b/app/src/main/java/com/nuvio/tv/ui/screens/home/HomeViewModel.kt @@ -31,6 +31,9 @@ class HomeViewModel @Inject constructor( private val _uiState = MutableStateFlow(HomeUiState()) val uiState: StateFlow = _uiState.asStateFlow() + private val _focusState = MutableStateFlow(HomeScreenFocusState()) + val focusState: StateFlow = _focusState.asStateFlow() + private val catalogsMap = linkedMapOf() private val catalogOrder = mutableListOf() @@ -190,4 +193,30 @@ class HomeViewModel @Inject constructor( private fun CatalogDescriptor.isSearchOnlyCatalog(): Boolean { return extra.any { extra -> extra.name == "search" && extra.isRequired } } + + /** + * Saves the current focus and scroll state for restoration when returning to this screen. + */ + fun saveFocusState( + verticalScrollIndex: Int, + verticalScrollOffset: Int, + focusedRowIndex: Int, + focusedItemIndex: Int, + catalogRowScrollStates: Map + ) { + _focusState.value = HomeScreenFocusState( + verticalScrollIndex = verticalScrollIndex, + verticalScrollOffset = verticalScrollOffset, + focusedRowIndex = focusedRowIndex, + focusedItemIndex = focusedItemIndex, + catalogRowScrollStates = catalogRowScrollStates + ) + } + + /** + * Clears the saved focus state. + */ + fun clearFocusState() { + _focusState.value = HomeScreenFocusState() + } }