Updated on 2026-08-14
This commit is contained in:
parent
679469c91f
commit
8737ebd291
15 changed files with 674 additions and 0 deletions
1
core/pagination/.gitignore
vendored
Normal file
1
core/pagination/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
10
core/pagination/build.gradle.kts
Normal file
10
core/pagination/build.gradle.kts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// region Coroutines
|
||||
implementation(deps.kotlin.coroutines)
|
||||
// endregion
|
||||
}
|
||||
13
core/pagination/src/main/java/com/tangem/pagination/Batch.kt
Normal file
13
core/pagination/src/main/java/com/tangem/pagination/Batch.kt
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.pagination
|
||||
|
||||
/**
|
||||
* Represents a batch of data with a key.
|
||||
* Used in [BatchListState].
|
||||
*
|
||||
* @param K type of the key.
|
||||
* @param T type of the data.
|
||||
*/
|
||||
data class Batch<K, T>(
|
||||
val key: K,
|
||||
val data: T,
|
||||
)
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package com.tangem.pagination
|
||||
|
||||
/**
|
||||
* Action that can be dispatched to [BatchListSource].
|
||||
*
|
||||
* @param R type of the request to load batches.
|
||||
* @param K type of the key of the batch.
|
||||
* @param U type of the update request.
|
||||
*/
|
||||
sealed class BatchAction<R, K, U> {
|
||||
|
||||
/**
|
||||
* Action to load the first batch.
|
||||
*
|
||||
* @param request request to load the first batch.
|
||||
*/
|
||||
data class Reload<R>(
|
||||
val request: R,
|
||||
) : BatchAction<R, Nothing, Nothing>()
|
||||
|
||||
/**
|
||||
* Action to load the next batch.
|
||||
*
|
||||
* @param request request to load the next batch with new request.
|
||||
* If null, the last request will be used.
|
||||
* Will be saved in the state and used for future LoadMore actions with request = null.
|
||||
*/
|
||||
data class LoadMore<R>(
|
||||
val request: R? = null,
|
||||
) : BatchAction<R, Nothing, Nothing>()
|
||||
|
||||
/**
|
||||
* Action to update the batch.
|
||||
*
|
||||
* @param keys keys of the batches to update.
|
||||
* @param request request to update the batches.
|
||||
*/
|
||||
class UpdateBatches<K, U>(
|
||||
val keys: Set<K>,
|
||||
val request: U,
|
||||
) : BatchAction<Nothing, K, U>()
|
||||
|
||||
/**
|
||||
* Action to cancel the current batch loading.
|
||||
*/
|
||||
data object CancelBatchLoading : BatchAction<Nothing, Nothing, Nothing>()
|
||||
|
||||
/**
|
||||
* Action to cancel all update requests.
|
||||
*/
|
||||
data object CancelAllUpdates : BatchAction<Nothing, Nothing, Nothing>()
|
||||
|
||||
/**
|
||||
* Action to cancel update requests that satisfy the predicate.
|
||||
*
|
||||
* @param predicate predicate to check if the update request should be cancelled.
|
||||
*/
|
||||
class CancelUpdates<K, U>(
|
||||
val predicate: (UpdateBatches<K, U>) -> Boolean,
|
||||
) : BatchAction<Nothing, K, U>()
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.tangem.pagination
|
||||
|
||||
/**
|
||||
* Represents a result of a batch fetch request.
|
||||
* Used in [BatchListState].
|
||||
*
|
||||
* @param T type of the data.
|
||||
* @param E type of the error.
|
||||
*/
|
||||
sealed class BatchFetchResult<out T, out E> {
|
||||
|
||||
/**
|
||||
* Represents a successful result of a batch fetch request.
|
||||
*
|
||||
* @param data fetched data.
|
||||
* @param last indicates if this is the last batch for the request.
|
||||
*/
|
||||
data class Success<T>(
|
||||
val data: T,
|
||||
val last: Boolean = false,
|
||||
) : BatchFetchResult<T, Nothing>()
|
||||
|
||||
/**
|
||||
* Represents an error result of a batch fetch request.
|
||||
*
|
||||
* @param error error that occurred during the request.
|
||||
*/
|
||||
data class Error<E>(val error: E) : BatchFetchResult<Nothing, E>()
|
||||
|
||||
/**
|
||||
* Represents an unknown error result of a batch fetch request.
|
||||
* Used for unexpected exceptions that occurred in fetch method in [BatchFetcher].
|
||||
*
|
||||
* @param throwable throwable that occurred during the request.
|
||||
*/
|
||||
class UnknownError(val throwable: Throwable) : BatchFetchResult<Nothing, Nothing>()
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.tangem.pagination
|
||||
|
||||
/**
|
||||
* Represents the result of a batch fetch operation.
|
||||
* Used in [BatchListState] and [BatchUpdateFetcher].
|
||||
*
|
||||
* @param TKey type of the key.
|
||||
* @param TData type of the data.
|
||||
* @param TError type of the error.
|
||||
*/
|
||||
sealed class BatchFetchUpdateResult<out TKey, out TData, out TError> {
|
||||
|
||||
/**
|
||||
* Represents a successful result of a batch update operation.
|
||||
*
|
||||
* @param data fetched data.
|
||||
*/
|
||||
data class Success<TKey, TData>(
|
||||
val data: List<Batch<TKey, TData>>,
|
||||
) : BatchFetchUpdateResult<TKey, TData, Nothing>()
|
||||
|
||||
/**
|
||||
* Represents an error result of a batch update operation.
|
||||
*
|
||||
* @param error error that occurred during the operation.
|
||||
*/
|
||||
data class Error<TError>(val error: TError) : BatchFetchUpdateResult<Nothing, Nothing, TError>()
|
||||
|
||||
/**
|
||||
* Represents an unknown error result of a batch update operation.
|
||||
* Used for unexpected exceptions that occurred in `fetchUpdate` method in [BatchUpdateFetcher].
|
||||
*
|
||||
* @param throwable throwable that occurred during the operation.
|
||||
*/
|
||||
class UnknownError(val throwable: Throwable) : BatchFetchUpdateResult<Nothing, Nothing, Nothing>()
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.pagination
|
||||
|
||||
/**
|
||||
* Interface for fetching a batch of data. Used in [BatchListState].
|
||||
*
|
||||
* @param TRequest type of the request.
|
||||
* @param TData type of the data.
|
||||
* @param TError type of the error.
|
||||
*
|
||||
* @see BatchListState
|
||||
*/
|
||||
interface BatchFetcher<TRequest, TData, TError> {
|
||||
|
||||
/**
|
||||
* Fetches a batch of data.
|
||||
*
|
||||
* @param request request to fetch the data.
|
||||
* @return result of the fetch operation.
|
||||
*/
|
||||
suspend fun fetch(request: BatchRequest<TRequest>): BatchFetchResult<TData, TError>
|
||||
}
|
||||
|
|
@ -0,0 +1,343 @@
|
|||
package com.tangem.pagination
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
/**
|
||||
* Source for paginated data. The starting point for pagination.
|
||||
*
|
||||
* @param TKey Type of the key that identifies a batch.
|
||||
* @param TData Type of the data in the batch. Generally, it' a list of items.
|
||||
* @param TUpdate Type of the update request.
|
||||
* @param TError Type of the error that can occur during fetching or updating.
|
||||
* @property state State of the paginated data.
|
||||
* @property updateResults Flow of results of update requests.
|
||||
*/
|
||||
interface BatchListSource<TKey, TData, TUpdate, TError> {
|
||||
val state: StateFlow<BatchListState<TKey, TData, TError>>
|
||||
val updateResults: SharedFlow<Pair<TUpdate, BatchFetchUpdateResult<TKey, TData, TError>>>
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new [BatchListSource] with the provided configuration.
|
||||
*
|
||||
* @param config Configuration for batching.
|
||||
* @param context Context for batching.
|
||||
* @param generateNewKey Function to generate a new key for a batch.
|
||||
* @param batchFetcher Function to fetch a batch of data.
|
||||
*
|
||||
* @return New instance of [BatchListSource].
|
||||
*/
|
||||
@Suppress("FunctionNaming")
|
||||
fun <TKey, TData, TRequest, TError> BatchListSource(
|
||||
config: BatchingConfig,
|
||||
context: BatchingContext<TRequest, TKey, Nothing>,
|
||||
generateNewKey: suspend (List<TKey>) -> TKey,
|
||||
batchFetcher: BatchFetcher<TRequest, TData, TError>,
|
||||
): BatchListSource<TKey, TData, Nothing, TError> =
|
||||
BatchListSourceImpl(config, context, generateNewKey, batchFetcher, null)
|
||||
|
||||
/**
|
||||
* Creates a new [BatchListSource] with the provided configuration.
|
||||
*
|
||||
* @param config Configuration for batching.
|
||||
* @param context Context for batching.
|
||||
* @param generateNewKey Function to generate a new key for a batch.
|
||||
* @param batchFetcher Function to fetch a batch of data.
|
||||
* @param updateFetcher Function to fetch updates for batches.
|
||||
*
|
||||
* @return New instance of [BatchListSource].
|
||||
*/
|
||||
@Suppress("FunctionNaming")
|
||||
fun <TKey, TData, TUpdate, TRequest, TError> BatchListSource(
|
||||
config: BatchingConfig,
|
||||
context: BatchingContext<TRequest, TKey, TUpdate>,
|
||||
generateNewKey: suspend (List<TKey>) -> TKey,
|
||||
batchFetcher: BatchFetcher<TRequest, TData, TError>,
|
||||
updateFetcher: BatchUpdateFetcher<TKey, TData, TError, TUpdate>,
|
||||
): BatchListSource<TKey, TData, TUpdate, TError> =
|
||||
BatchListSourceImpl(config, context, generateNewKey, batchFetcher, updateFetcher)
|
||||
|
||||
private class BatchListSourceImpl<TKey, TData, TUpdate, TRequest, TError>(
|
||||
private val config: BatchingConfig,
|
||||
private val context: BatchingContext<TRequest, TKey, TUpdate>,
|
||||
private val generateNewKey: suspend (List<TKey>) -> TKey,
|
||||
private val batchFetcher: BatchFetcher<TRequest, TData, TError>,
|
||||
private val updateFetcher: BatchUpdateFetcher<TKey, TData, TError, TUpdate>? = null,
|
||||
) : BatchListSource<TKey, TData, TUpdate, TError> {
|
||||
|
||||
override val state = MutableStateFlow(BatchListState<TKey, TData, TError>(emptyList(), PaginationStatus.None))
|
||||
override val updateResults = MutableSharedFlow<Pair<TUpdate, BatchFetchUpdateResult<TKey, TData, TError>>>(
|
||||
extraBufferCapacity = 1,
|
||||
onBufferOverflow = BufferOverflow.DROP_OLDEST,
|
||||
)
|
||||
|
||||
private val scope = context.coroutineScope
|
||||
private val updateJobs = MutableStateFlow<List<Pair<BatchAction.UpdateBatches<TKey, TUpdate>, Job>>>(emptyList())
|
||||
private val waitingUpdateJobs =
|
||||
MutableStateFlow<List<Pair<BatchAction.UpdateBatches<TKey, TUpdate>, Job>>>(emptyList())
|
||||
|
||||
private val lastRequest = MutableStateFlow<BatchRequest<TRequest>?>(null)
|
||||
private var reloadActionJob: Job? = null
|
||||
private var loadMoreActionJob: Job? = null
|
||||
|
||||
init {
|
||||
scope.launch {
|
||||
try {
|
||||
awaitCancellation()
|
||||
} finally {
|
||||
withContext(NonCancellable) {
|
||||
lastRequest.value = null
|
||||
loadMoreActionJob = null
|
||||
loadMoreActionJob = null
|
||||
lastRequest.value = null
|
||||
stopAllUpdates()
|
||||
state.value = BatchListState(emptyList(), PaginationStatus.None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope.launch {
|
||||
context.actionsFlow.collect { action ->
|
||||
collectActions(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectActions(action: BatchAction<TRequest, TKey, TUpdate>) {
|
||||
when (action) {
|
||||
is BatchAction.Reload -> {
|
||||
// Stop all tasks
|
||||
loadMoreActionJob?.cancel()
|
||||
reloadActionJob?.cancel()
|
||||
stopAllUpdates()
|
||||
reloadActionJob = scope.launch(Dispatchers.IO) {
|
||||
reloadTask(action)
|
||||
}
|
||||
}
|
||||
is BatchAction.LoadMore -> {
|
||||
if (loadMoreActionJob?.isActive == true) {
|
||||
return
|
||||
}
|
||||
|
||||
loadMoreActionJob = scope.launch(Dispatchers.IO) {
|
||||
reloadActionJob?.join()
|
||||
loadMoreTask(action)
|
||||
}
|
||||
}
|
||||
is BatchAction.UpdateBatches -> {
|
||||
if (updateFetcher == null) return
|
||||
|
||||
scope.launch(Dispatchers.IO) {
|
||||
val job = launch(start = CoroutineStart.LAZY) {
|
||||
updateBatchesTask(action)
|
||||
}
|
||||
|
||||
val actionJob = action to job
|
||||
|
||||
waitingUpdateJobs.update { it + actionJob }
|
||||
|
||||
updateJobs.first { workingJobs ->
|
||||
action.keys.intersect(workingJobs.map { it.first.keys }.flatten().toSet()).isEmpty()
|
||||
}
|
||||
|
||||
waitingUpdateJobs.update { it - actionJob }
|
||||
|
||||
val started = job.start()
|
||||
|
||||
if (started) {
|
||||
updateJobs.update { it + actionJob }
|
||||
|
||||
job.invokeOnCompletion { cause ->
|
||||
if (cause !is CancellationException) {
|
||||
updateJobs.update { it - actionJob }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BatchAction.CancelAllUpdates -> {
|
||||
if (updateFetcher == null) return
|
||||
stopAllUpdates()
|
||||
}
|
||||
is BatchAction.CancelUpdates -> {
|
||||
if (updateFetcher == null) return
|
||||
stopUpdates(action.predicate)
|
||||
}
|
||||
BatchAction.CancelBatchLoading -> {
|
||||
loadMoreActionJob?.cancel()
|
||||
reloadActionJob?.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun reloadTask(action: BatchAction.Reload<TRequest>) {
|
||||
state.value = BatchListState(
|
||||
data = emptyList(),
|
||||
status = PaginationStatus.InitialLoading,
|
||||
)
|
||||
|
||||
val requestData = action.request
|
||||
val request = BatchRequest(offset = 0, limit = config.batchSize, requestData)
|
||||
|
||||
val res = runCatching {
|
||||
batchFetcher.fetch(request)
|
||||
}.getOrElse { BatchFetchResult.UnknownError(it) }
|
||||
|
||||
state.value = if (res is BatchFetchResult.Success) {
|
||||
val key = generateNewKey(listOf())
|
||||
val batch = Batch(
|
||||
key = key,
|
||||
data = res.data,
|
||||
)
|
||||
BatchListState(
|
||||
data = listOf(batch),
|
||||
status = if (res.last) {
|
||||
PaginationStatus.EndOfPagination
|
||||
} else {
|
||||
PaginationStatus.Paginating(res)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
BatchListState(
|
||||
data = emptyList(),
|
||||
status = PaginationStatus.InitialLoadingError(
|
||||
error = (res as? BatchFetchResult.Error)?.error,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
lastRequest.value = request
|
||||
}
|
||||
|
||||
private suspend fun loadMoreTask(action: BatchAction.LoadMore<TRequest>) {
|
||||
val status = state.value.status
|
||||
val lastReq = lastRequest.value
|
||||
|
||||
val request: BatchRequest<TRequest> = when {
|
||||
// try to continue pagination with new request
|
||||
status is PaginationStatus.EndOfPagination && action.request != null && action.request != lastReq -> {
|
||||
requireNotNull(lastReq)
|
||||
|
||||
BatchRequest(
|
||||
offset = lastReq.offset + lastReq.limit,
|
||||
limit = config.batchSize,
|
||||
data = action.request,
|
||||
)
|
||||
}
|
||||
// continue pagination
|
||||
status is PaginationStatus.Paginating -> {
|
||||
requireNotNull(lastReq)
|
||||
|
||||
if (status.lastResult is BatchFetchResult.Success) {
|
||||
BatchRequest(
|
||||
offset = lastReq.offset + lastReq.limit,
|
||||
limit = config.batchSize,
|
||||
data = action.request ?: lastReq.data,
|
||||
)
|
||||
} else {
|
||||
BatchRequest(
|
||||
offset = lastReq.offset,
|
||||
limit = lastReq.limit,
|
||||
data = action.request ?: lastReq.data,
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> return
|
||||
}
|
||||
|
||||
state.update { it.copy(status = PaginationStatus.NextBatchLoading) }
|
||||
|
||||
val res = runCatching {
|
||||
batchFetcher.fetch(request)
|
||||
}.getOrElse { BatchFetchResult.UnknownError(it) }
|
||||
|
||||
lastRequest.value = request
|
||||
|
||||
state.update { currentState ->
|
||||
if (res is BatchFetchResult.Success) {
|
||||
val newBatch = Batch(
|
||||
key = generateNewKey(currentState.data.map { it.key }),
|
||||
data = res.data,
|
||||
)
|
||||
|
||||
currentState.copy(
|
||||
data = currentState.data + newBatch,
|
||||
status = if (res.last) {
|
||||
PaginationStatus.EndOfPagination
|
||||
} else {
|
||||
PaginationStatus.Paginating(res)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
currentState.copy(
|
||||
status = PaginationStatus.Paginating(res),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateBatchesTask(action: BatchAction.UpdateBatches<TKey, TUpdate>) {
|
||||
if (updateFetcher == null) return
|
||||
|
||||
val batches = state.value.data
|
||||
val batchesToUpdate = batches.filter { action.keys.contains(it.key) }
|
||||
|
||||
val result = updateFetcher.fetchUpdate(
|
||||
toUpdate = batchesToUpdate,
|
||||
updateRequest = action.request,
|
||||
)
|
||||
|
||||
if (result is BatchFetchUpdateResult.Success) {
|
||||
state.update { currentState ->
|
||||
val resMap = result.data.associateBy { it.key }
|
||||
currentState.copy(
|
||||
data = currentState.data.map {
|
||||
resMap[it.key] ?: it
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
updateResults.emit(action.request to result)
|
||||
}
|
||||
|
||||
private fun stopAllUpdates() {
|
||||
updateJobs.update { actionJobs ->
|
||||
waitingUpdateJobs.update { waitingActionJobs ->
|
||||
waitingActionJobs.forEach {
|
||||
it.second.cancel()
|
||||
}
|
||||
emptyList()
|
||||
}
|
||||
actionJobs.forEach {
|
||||
it.second.cancel()
|
||||
}
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopUpdates(predicate: (BatchAction.UpdateBatches<TKey, TUpdate>) -> Boolean) {
|
||||
updateJobs.update { actionJobs ->
|
||||
waitingUpdateJobs.update { waitingActionJobs ->
|
||||
waitingActionJobs.mapNotNull {
|
||||
if (predicate(it.first)) {
|
||||
it.second.cancel()
|
||||
null
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
actionJobs.mapNotNull {
|
||||
if (predicate(it.first)) {
|
||||
it.second.cancel()
|
||||
null
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.pagination
|
||||
|
||||
/**
|
||||
* State that is used for listening the current state of a pagination.
|
||||
*
|
||||
* @param K type of the key of the batch.
|
||||
* @param T type of the data.
|
||||
* @param E type of the error.
|
||||
*
|
||||
* @property data list of loaded batches.
|
||||
* @property status current status of the pagination.
|
||||
*
|
||||
* @see BatchListSource
|
||||
*/
|
||||
data class BatchListState<K, T, E>(
|
||||
val data: List<Batch<K, T>>,
|
||||
val status: PaginationStatus<T, E>,
|
||||
)
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.pagination
|
||||
|
||||
/**
|
||||
* Request to fetch a batch of data.
|
||||
*
|
||||
* @param R type of the request.
|
||||
*
|
||||
* @property offset offset for the request.
|
||||
* @property limit limit for the request.
|
||||
* @property data body of the request.
|
||||
*
|
||||
* @see BatchFetcher
|
||||
*/
|
||||
data class BatchRequest<R>(
|
||||
val offset: Int,
|
||||
val limit: Int,
|
||||
val data: R,
|
||||
)
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.pagination
|
||||
|
||||
/**
|
||||
* Interface for fetching updates for a batch of data.
|
||||
* Used in [BatchListState].
|
||||
*
|
||||
* @param TKey type of the key.
|
||||
* @param TData type of the data.
|
||||
* @param TError type of the error.
|
||||
* @param TUpdate type of the update request.
|
||||
*/
|
||||
interface BatchUpdateFetcher<TKey, TData, TError, TUpdate> {
|
||||
|
||||
/**
|
||||
* Fetches updates for a batch of data.
|
||||
*
|
||||
* @param toUpdate list of batches to update.
|
||||
* @param updateRequest request to update the data.
|
||||
* @return result of the update operation.
|
||||
*/
|
||||
suspend fun fetchUpdate(
|
||||
toUpdate: List<Batch<TKey, TData>>,
|
||||
updateRequest: TUpdate,
|
||||
): BatchFetchUpdateResult<TKey, TData, TError>
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.pagination
|
||||
|
||||
/**
|
||||
* Configuration for batching.
|
||||
*
|
||||
* @param batchSize size of the batch.
|
||||
* @param prefetchDistance number of items to fetch for the first batch.
|
||||
*/
|
||||
data class BatchingConfig(
|
||||
val batchSize: Int,
|
||||
val prefetchDistance: Int = batchSize,
|
||||
)
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.pagination
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* Context for working with [BatchListSource].
|
||||
*
|
||||
* @param R type of the request.
|
||||
* @param K type of the key.
|
||||
* @param U type of the update request.
|
||||
*
|
||||
* @property actionsFlow flow of [BatchAction]s that would be dispatched to [BatchListSource].
|
||||
* @property coroutineScope scope for the [BatchListSource] to launch coroutines. When it is cancelled,
|
||||
* all the operations and requests launched in the [BatchListSource] would be cancelled and all data would be cleared.
|
||||
*
|
||||
* @see BatchListSource
|
||||
*/
|
||||
class BatchingContext<R, K, U>(
|
||||
val actionsFlow: Flow<BatchAction<R, K, U>>,
|
||||
val coroutineScope: CoroutineScope,
|
||||
)
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package com.tangem.pagination
|
||||
|
||||
/**
|
||||
* Status of the pagination.
|
||||
*
|
||||
* @param T type of the data.
|
||||
* @param E type of the error.
|
||||
*
|
||||
* @see BatchListState
|
||||
*/
|
||||
sealed class PaginationStatus<out T, out E> {
|
||||
|
||||
/**
|
||||
* Represents that there is no data. Used when the list of batches is empty.
|
||||
* The initial state of the pagination.
|
||||
*/
|
||||
data object None : PaginationStatus<Nothing, Nothing>()
|
||||
|
||||
/**
|
||||
* Represents that the batch is loading for the first time.
|
||||
* Used when the pagination is empty and the first batch is being loaded.
|
||||
*/
|
||||
data object InitialLoading : PaginationStatus<Nothing, Nothing>()
|
||||
|
||||
/**
|
||||
* Represents that the first batch was loaded with an error.
|
||||
*
|
||||
* @param error error that occurred during the initial loading.
|
||||
*/
|
||||
data class InitialLoadingError<T, E>(
|
||||
val error: E?,
|
||||
) : PaginationStatus<T, E>()
|
||||
|
||||
/**
|
||||
* Represents that the last batch was loaded and
|
||||
* the source is ready to load the next one or reload previous if [lastResult] is an error.
|
||||
* For the first batch, [lastResult] is always [BatchFetchResult.Success]
|
||||
*
|
||||
* @param lastResult result of the last batch fetch.
|
||||
*/
|
||||
data class Paginating<out T, out E>(
|
||||
val lastResult: BatchFetchResult<T, E>,
|
||||
) : PaginationStatus<T, E>()
|
||||
|
||||
/**
|
||||
* Represents that the next batch is loading.
|
||||
* Used when the next batch is being loaded.
|
||||
*/
|
||||
data object NextBatchLoading : PaginationStatus<Nothing, Nothing>()
|
||||
|
||||
/**
|
||||
* Represents that the source has no more batches to load.
|
||||
* The next [BatchAction.LoadMore] with [BatchAction.LoadMore.request] = null will be ignored.
|
||||
*/
|
||||
data object EndOfPagination : PaginationStatus<Nothing, Nothing>()
|
||||
}
|
||||
|
|
@ -127,6 +127,7 @@ include(":core:utils")
|
|||
include(":core:deep-links")
|
||||
include(":core:deep-links:global")
|
||||
include(":core:decompose")
|
||||
include(":core:pagination")
|
||||
// endregion Core modules
|
||||
|
||||
// region Common modules
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue