diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogModels.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogModels.kt index c136a0956..da473cb27 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogModels.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogModels.kt @@ -11,3 +11,8 @@ data class CatalogUiState( val canLoadMore: Boolean get() = nextSkip != null } + +data class CatalogScrollPosition( + val firstVisibleItemIndex: Int = 0, + val firstVisibleItemScrollOffset: Int = 0, +) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogRepository.kt index 4af61b57e..716346a88 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogRepository.kt @@ -25,6 +25,7 @@ object CatalogRepository { private var activeJob: Job? = null private var activeRequest: CatalogRequest? = null + private val scrollPositions = linkedMapOf() fun load( manifestUrl: String, @@ -34,7 +35,7 @@ object CatalogRepository { supportsPagination: Boolean = false, force: Boolean = false, ) { - val request = CatalogRequest( + val request = catalogRequest( manifestUrl = manifestUrl, type = type, catalogId = catalogId, @@ -62,9 +63,36 @@ object CatalogRepository { fun clear() { activeJob?.cancel() activeRequest = null + scrollPositions.clear() _uiState.value = CatalogUiState() } + fun scrollPosition( + manifestUrl: String, + type: String, + catalogId: String, + genre: String? = null, + supportsPagination: Boolean = false, + ): CatalogScrollPosition = + scrollPositions[catalogRequest(manifestUrl, type, catalogId, genre, supportsPagination)] + ?: CatalogScrollPosition() + + fun saveScrollPosition( + manifestUrl: String, + type: String, + catalogId: String, + genre: String? = null, + supportsPagination: Boolean = false, + firstVisibleItemIndex: Int, + firstVisibleItemScrollOffset: Int, + ) { + val request = catalogRequest(manifestUrl, type, catalogId, genre, supportsPagination) + scrollPositions[request] = CatalogScrollPosition( + firstVisibleItemIndex = firstVisibleItemIndex, + firstVisibleItemScrollOffset = firstVisibleItemScrollOffset, + ) + } + private fun fetchInternalLibrary(request: CatalogRequest) { activeJob?.cancel() _uiState.value = _uiState.value.copy( @@ -127,7 +155,7 @@ object CatalogRepository { catalogId = request.catalogId, genre = request.genre, skip = requestedSkip.takeIf { it > 0 }, - ).withUnreleasedFilter() + ).withUnreleasedFilter(request.hideUnreleasedContent) }.fold( onSuccess = { page -> if (activeRequest != request) return@fold @@ -159,10 +187,26 @@ object CatalogRepository { ) } } + + private fun catalogRequest( + manifestUrl: String, + type: String, + catalogId: String, + genre: String? = null, + supportsPagination: Boolean = false, + ): CatalogRequest = + CatalogRequest( + manifestUrl = manifestUrl, + type = type, + catalogId = catalogId, + genre = genre, + supportsPagination = supportsPagination, + hideUnreleasedContent = HomeCatalogSettingsRepository.snapshot().hideUnreleasedContent, + ) } -private fun CatalogPage.withUnreleasedFilter(): CatalogPage { - if (!HomeCatalogSettingsRepository.snapshot().hideUnreleasedContent) return this +private fun CatalogPage.withUnreleasedFilter(hideUnreleasedContent: Boolean): CatalogPage { + if (!hideUnreleasedContent) return this val filteredItems = items.filterReleasedItems(CurrentDateProvider.todayIsoDate()) return if (filteredItems.size == items.size) this else copy(items = filteredItems) } @@ -173,4 +217,5 @@ private data class CatalogRequest( val catalogId: String, val genre: String?, val supportsPagination: Boolean, + val hideUnreleasedContent: Boolean, ) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogScreen.kt index e068aa4e4..e20cbbbac 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogScreen.kt @@ -86,7 +86,26 @@ fun CatalogScreen( WatchedRepository.ensureLoaded() WatchedRepository.uiState }.collectAsStateWithLifecycle() - val gridState = rememberLazyGridState() + val initialScrollPosition = remember( + manifestUrl, + type, + catalogId, + genre, + supportsPagination, + homeCatalogSettingsUiState.hideUnreleasedContent, + ) { + CatalogRepository.scrollPosition( + manifestUrl = manifestUrl, + type = type, + catalogId = catalogId, + genre = genre, + supportsPagination = supportsPagination, + ) + } + val gridState = rememberLazyGridState( + initialFirstVisibleItemIndex = initialScrollPosition.firstVisibleItemIndex, + initialFirstVisibleItemScrollOffset = initialScrollPosition.firstVisibleItemScrollOffset, + ) var headerHeightPx by remember { mutableIntStateOf(0) } var observedOfflineState by remember { mutableStateOf(false) } @@ -97,10 +116,25 @@ fun CatalogScreen( catalogId = catalogId, genre = genre, supportsPagination = supportsPagination, - force = true, ) } + LaunchedEffect(gridState, manifestUrl, type, catalogId, genre, supportsPagination, homeCatalogSettingsUiState.hideUnreleasedContent) { + snapshotFlow { gridState.firstVisibleItemIndex to gridState.firstVisibleItemScrollOffset } + .distinctUntilChanged() + .collect { (index, offset) -> + CatalogRepository.saveScrollPosition( + manifestUrl = manifestUrl, + type = type, + catalogId = catalogId, + genre = genre, + supportsPagination = supportsPagination, + firstVisibleItemIndex = index, + firstVisibleItemScrollOffset = offset, + ) + } + } + LaunchedEffect(gridState, uiState.canLoadMore, uiState.isLoading) { snapshotFlow { gridState.layoutInfo } .map { layoutInfo -> diff --git a/composeApp/src/iosMain/kotlin/com/nuvio/app/features/home/components/CollectionCardRemoteImage.ios.kt b/composeApp/src/iosMain/kotlin/com/nuvio/app/features/home/components/CollectionCardRemoteImage.ios.kt index 54cb6af12..7f1e5c69e 100644 --- a/composeApp/src/iosMain/kotlin/com/nuvio/app/features/home/components/CollectionCardRemoteImage.ios.kt +++ b/composeApp/src/iosMain/kotlin/com/nuvio/app/features/home/components/CollectionCardRemoteImage.ios.kt @@ -96,7 +96,6 @@ internal actual fun CollectionCardRemoteImage( UIKitView( modifier = modifier, - interactive = false, factory = { UIImageView().apply { contentMode = UIViewContentMode.UIViewContentModeScaleAspectFill diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 597dd1f10..39ae4c826 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,10 +9,10 @@ androidx-appcompat = "1.7.1" androidx-core = "1.17.0" androidx-core-splashscreen = "1.0.1" androidx-espresso = "3.7.0" -androidx-lifecycle = "2.11.0-alpha03" +androidx-lifecycle = "2.11.0-beta01" androidx-work = "2.10.3" androidx-testExt = "1.3.0" -composeMultiplatform = "1.11.0-beta03" +composeMultiplatform = "1.11.1" coil = "3.5.0-beta01" kermit = "2.0.5" junit = "4.13.2"