From 800dab5be06737f786c008844c33baadfc255c77 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 4 Mar 2025 09:33:37 +0600 Subject: [PATCH] rework of PagedComponent --- .../pagination/PaginationResult.kt | 2 +- .../pagination/SimplePagination.kt | 10 +++ .../src/commonMain/kotlin/PagedComponent.kt | 90 +++++-------------- 3 files changed, 32 insertions(+), 70 deletions(-) diff --git a/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/PaginationResult.kt b/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/PaginationResult.kt index 217fff6006d..30026faa1f1 100644 --- a/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/PaginationResult.kt +++ b/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/PaginationResult.kt @@ -32,7 +32,7 @@ data class PaginationResult( page: Int, results: List, pagesNumber: Int, - size: Int + size: Int = results.size ) : this( page, size, diff --git a/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/SimplePagination.kt b/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/SimplePagination.kt index 11d2d90fbfd..cde64ffeb1f 100644 --- a/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/SimplePagination.kt +++ b/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/SimplePagination.kt @@ -26,6 +26,16 @@ inline fun Pagination.nextPage() = size ) +/** + * This method DO NOT check [Pagination.page] of receiver. Returns pagination for previous page + */ +@Suppress("NOTHING_TO_INLINE") +inline fun Pagination.previousPage() = + SimplePagination( + page - 1, + size + ) + /** * @param page Current page number * @param size Current page size diff --git a/pagination/compose/src/commonMain/kotlin/PagedComponent.kt b/pagination/compose/src/commonMain/kotlin/PagedComponent.kt index e901ab1def0..9f13388d06c 100644 --- a/pagination/compose/src/commonMain/kotlin/PagedComponent.kt +++ b/pagination/compose/src/commonMain/kotlin/PagedComponent.kt @@ -1,9 +1,7 @@ package dev.inmo.micro_utils.pagination.compose import androidx.compose.runtime.* -import dev.inmo.micro_utils.common.Optional -import dev.inmo.micro_utils.common.dataOrThrow -import dev.inmo.micro_utils.common.optional +import dev.inmo.micro_utils.coroutines.SpecialMutableStateFlow import dev.inmo.micro_utils.pagination.* /** @@ -19,23 +17,21 @@ import dev.inmo.micro_utils.pagination.* * @param size Number of items per page. */ class PagedComponentContext internal constructor( - preset: PaginationResult? = null, initialPage: Int, size: Int ) { - internal val iterationState: MutableState = mutableStateOf(SimplePagination(preset?.page ?: initialPage, preset?.size ?: size)) - - internal var dataOptional: PaginationResult? = preset - private set - internal val dataState: MutableState?> = mutableStateOf(dataOptional) + internal val startPage = SimplePagination(initialPage, size) + internal val currentlyLoadingPageState = SpecialMutableStateFlow(startPage) + internal val latestLoadedPage = SpecialMutableStateFlow?>(null) /** * Loads the next page of data. If the last page is reached, this function returns early. */ fun loadNext() { - iterationState.value = iterationState.value.let { - if (dataState.value ?.isLastPage == true) return - it.nextPage() + when { + currentlyLoadingPageState.value != null -> return + latestLoadedPage.value ?.isLastPage == true -> return + else -> currentlyLoadingPageState.value = (latestLoadedPage.value ?.nextPage()) ?: startPage } } @@ -43,12 +39,10 @@ class PagedComponentContext internal constructor( * Loads the previous page of data if available. */ fun loadPrevious() { - iterationState.value = iterationState.value.let { - if (it.isFirstPage) return - SimplePagination( - it.page - 1, - it.size - ) + when { + currentlyLoadingPageState.value != null -> return + latestLoadedPage.value ?.isFirstPage == true -> return + else -> currentlyLoadingPageState.value = (latestLoadedPage.value ?.previousPage()) ?: startPage } } @@ -56,9 +50,7 @@ class PagedComponentContext internal constructor( * Reloads the current page, refreshing the data. */ fun reload() { - iterationState.value = iterationState.value.let { - SimplePagination(it.page, it.size) - } + currentlyLoadingPageState.value = latestLoadedPage.value } } @@ -74,46 +66,26 @@ class PagedComponentContext internal constructor( */ @Composable internal fun PagedComponent( - preload: PaginationResult?, initialPage: Int, size: Int, loader: suspend PagedComponentContext.(Pagination) -> PaginationResult, block: @Composable PagedComponentContext.(PaginationResult) -> Unit ) { - val context = remember { PagedComponentContext(preload, initialPage, size) } + val context = remember { PagedComponentContext(initialPage, size) } - LaunchedEffect(context.iterationState.value.page, context.iterationState.value.hashCode()) { - context.dataState.value = loader(context, context.iterationState.value) + val currentlyLoadingState = context.currentlyLoadingPageState.collectAsState() + LaunchedEffect(currentlyLoadingState.value) { + val paginationResult = loader(context, currentlyLoadingState.value ?: return@LaunchedEffect) + context.latestLoadedPage.value = paginationResult + context.currentlyLoadingPageState.value = null } - context.dataState.value ?.let { + val pageState = context.latestLoadedPage.collectAsState() + pageState.value ?.let { context.block(it) } } -/** - * Overloaded composable function for paginated components with preloaded data. - * - * @param T The type of paginated data. - * @param preload Preloaded pagination result. - * @param loader Suspended function that loads paginated data. - * @param block Composable function that renders the UI with the loaded data. - */ -@Composable -fun PagedComponent( - preload: PaginationResult, - loader: suspend PagedComponentContext.(Pagination) -> PaginationResult, - block: @Composable PagedComponentContext.(PaginationResult) -> Unit -) { - PagedComponent( - preload, - preload.page, - preload.size, - loader, - block - ) -} - /** * Overloaded composable function for paginated components with pagination info. * @@ -129,7 +101,6 @@ fun PagedComponent( block: @Composable PagedComponentContext.(PaginationResult) -> Unit ) { PagedComponent( - null, pageInfo.page, pageInfo.size, loader, @@ -137,25 +108,6 @@ fun PagedComponent( ) } -/** - * Overloaded composable function for paginated components with an initial page. - * - * @param T The type of paginated data. - * @param initialPage Initial page number. - * @param size Number of items per page. - * @param loader Suspended function that loads paginated data. - * @param block Composable function that renders the UI with the loaded data. - */ -@Composable -fun PagedComponent( - initialPage: Int, - size: Int, - loader: suspend PagedComponentContext.(Pagination) -> PaginationResult, - block: @Composable PagedComponentContext.(PaginationResult) -> Unit -) { - PagedComponent(null, initialPage, size, loader, block) -} - /** * Overloaded composable function for paginated components with only a size parameter. *