Created
August 16, 2025 05:28
-
-
Save VahidGarousi/c6238d198eb511755fa78b87ed67321c to your computer and use it in GitHub Desktop.
Pagination
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package ir.modjame.core.ui.paginator.manager | |
| import ir.modjame.core.common.util.DataError | |
| import ir.modjame.core.common.util.Result | |
| import ir.modjame.core.common.util.map | |
| import ir.modjame.core.domain.model.CursorPaginatedResult | |
| import ir.modjame.core.domain.model.PaginatedResult | |
| class CursorBasedPaginationManager<T>( | |
| private var initialCursor: String?, | |
| private val fetch: suspend (cursor: String) -> Result<CursorPaginatedResult<T>, DataError.Network>, | |
| ) : PaginationStrategy<T> { | |
| private var currentCursor: String? = initialCursor | |
| private var hasMore = true | |
| override suspend fun fetchNext(): Result<PaginatedResult<T>, DataError.Network> { | |
| if (!hasMore) return Result.Failure(DataError.Network.NOT_FOUND) | |
| return currentCursor?.let { cursor -> | |
| fetch(cursor).map { paginatedResult -> | |
| currentCursor = paginatedResult.nextCursor | |
| hasMore = paginatedResult.hasMore | |
| PaginatedResult( | |
| data = paginatedResult.posts, | |
| totalPages = if (hasMore) Int.MAX_VALUE else 1, | |
| ) | |
| } | |
| } ?: Result.Failure(DataError.Network.UNKNOWN) | |
| } | |
| override fun reset() { | |
| currentCursor = initialCursor | |
| hasMore = true | |
| } | |
| override fun hasMore(): Boolean = hasMore | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package ir.modjame.core.domain.model | |
| data class CursorPaginatedResult<T>( | |
| val posts: List<T>, | |
| val nextCursor: String?, | |
| val hasMore: Boolean | |
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package ir.modjame.core.ui.paginator.manager | |
| import ir.modjame.core.common.util.DataError | |
| import ir.modjame.core.common.util.Result | |
| import ir.modjame.core.common.util.onSuccess | |
| import ir.modjame.core.domain.model.PaginatedResult | |
| class PageBasedPaginationManager<T>( | |
| private val initialPage: Int = 1, | |
| private val fetch: suspend (page: Int) -> Result<PaginatedResult<T>, DataError.Network>, | |
| ) : PaginationStrategy<T> { | |
| private var currentPage = initialPage | |
| private var isLastPage = false | |
| override suspend fun fetchNext(): Result<PaginatedResult<T>, DataError.Network> { | |
| val result = fetch(currentPage) | |
| result.onSuccess { | |
| isLastPage = currentPage >= it.totalPages | |
| currentPage++ | |
| } | |
| return result | |
| } | |
| override fun reset() { | |
| currentPage = initialPage | |
| isLastPage = false | |
| } | |
| override fun hasMore() = !isLastPage | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package ir.modjame.core.domain.model | |
| data class PaginatedResult<T>( | |
| val data: List<T>, | |
| val totalPages: Int, | |
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package ir.modjame.core.ui.paginator.state | |
| import kotlinx.collections.immutable.ImmutableList | |
| sealed class PaginatedState<out T> { | |
| abstract val data: ImmutableList<T>? | |
| data object NotLoaded : PaginatedState<Nothing>() { | |
| override val data: Nothing? = null | |
| } | |
| data object InitialLoading : PaginatedState<Nothing>() { | |
| override val data: Nothing? = null | |
| } | |
| data class LoadingMore<T>( | |
| override val data: ImmutableList<T>, | |
| ) : PaginatedState<T>() | |
| data class Loaded<T>( | |
| override val data: ImmutableList<T>, | |
| val isEndReached: Boolean, | |
| ) : PaginatedState<T>() | |
| data class Error( | |
| val message: String, | |
| ) : PaginatedState<Nothing>() { | |
| override val data: ImmutableList<Nothing>? = null | |
| } | |
| } | |
| fun <T> PaginatedState<T>.hasMore(): Boolean = | |
| when (this) { | |
| is PaginatedState.Loaded -> !isEndReached | |
| is PaginatedState.NotLoaded, | |
| is PaginatedState.InitialLoading, | |
| is PaginatedState.LoadingMore, | |
| is PaginatedState.Error, | |
| -> true | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package ir.modjame.core.ui.paginator.manager | |
| import ir.modjame.core.common.util.fold | |
| import ir.modjame.core.ui.paginator.state.PaginatedState | |
| import kotlinx.collections.immutable.toPersistentList | |
| class PaginationManager<T>( | |
| private val strategy: PaginationStrategy<T>, | |
| private val onStateUpdated: (PaginatedState<T>) -> Unit, | |
| ) { | |
| private var isLoading = false | |
| private val allItems = mutableListOf<T>() | |
| suspend fun loadNextPage() { | |
| if (isLoading || !strategy.hasMore()) return | |
| isLoading = true | |
| if (allItems.isEmpty()) { | |
| onStateUpdated(PaginatedState.InitialLoading) | |
| } else { | |
| onStateUpdated(PaginatedState.LoadingMore(allItems.toPersistentList())) | |
| } | |
| strategy.fetchNext().fold( | |
| onSuccess = { paginatedResult -> | |
| allItems.addAll(paginatedResult.data) | |
| onStateUpdated( | |
| PaginatedState.Loaded( | |
| data = allItems.toPersistentList(), | |
| isEndReached = !strategy.hasMore(), | |
| ), | |
| ) | |
| }, | |
| onFailure = { error -> | |
| onStateUpdated(PaginatedState.Error(error.name)) | |
| }, | |
| ) | |
| isLoading = false | |
| } | |
| suspend fun refresh() { | |
| strategy.reset() | |
| allItems.clear() | |
| loadNextPage() | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package ir.modjame.core.ui.paginator.manager | |
| import ir.modjame.core.common.util.DataError | |
| import ir.modjame.core.common.util.Result | |
| import ir.modjame.core.domain.model.PaginatedResult | |
| interface PaginationStrategy<T> { | |
| suspend fun fetchNext(): Result<PaginatedResult<T>, DataError.Network> | |
| fun reset() | |
| fun hasMore(): Boolean | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment