diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/custom/FetchingStrategy.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/custom/FetchingStrategy.kt index 3b0a3ff..b69352a 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/custom/FetchingStrategy.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/custom/FetchingStrategy.kt @@ -17,7 +17,7 @@ import org.mobilenativefoundation.storex.paging.runtime.PagingState * @param ItemId The type of the item identifier. * @param PageRequestKey The type of the paging key. */ -interface FetchingStrategy { +interface FetchingStrategy { /** * Determines whether to fetch more data in the forward direction based on the current state of the pager. @@ -29,7 +29,7 @@ interface FetchingStrategy { */ fun shouldFetchForward( params: PagingSource.LoadParams, - pagingState: PagingState, + pagingState: PagingState, fetchingState: FetchingState, ): Boolean @@ -43,7 +43,7 @@ interface FetchingStrategy { */ fun shouldFetchBackward( params: PagingSource.LoadParams, - pagingState: PagingState, + pagingState: PagingState, fetchingState: FetchingState, ): Boolean } \ No newline at end of file diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Action.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Action.kt index e7c0529..487b4f5 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Action.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Action.kt @@ -1,25 +1,37 @@ package org.mobilenativefoundation.storex.paging.runtime -sealed class Action { +import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.MutableOperationPipeline + +sealed class Action { data class ProcessQueue internal constructor( val direction: LoadDirection - ) : Action() + ) : Action() data class SkipQueue internal constructor( val key: K, val direction: LoadDirection, val strategy: LoadStrategy, - ) : Action() + ) : Action() data class Enqueue internal constructor( val key: K, val direction: LoadDirection, val strategy: LoadStrategy, val jump: Boolean - ) : Action() + ) : Action() + + data object Invalidate : Action() + + data class AddOperation( + val operation: Operation + ) : Action() + + data class RemoveOperation( + val operation: Operation + ) : Action() - data object Invalidate : Action() + data object ClearOperations : Action() companion object { fun skipQueue( diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Dispatcher.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Dispatcher.kt index d2df9f1..ca882f1 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Dispatcher.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Dispatcher.kt @@ -1,5 +1,5 @@ package org.mobilenativefoundation.storex.paging.runtime -interface Dispatcher { - suspend fun dispatch(action: Action) +interface Dispatcher { + suspend fun dispatch(action: Action) } \ No newline at end of file diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/ExperimentalPagingApi.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/ExperimentalPagingApi.kt new file mode 100644 index 0000000..6fae646 --- /dev/null +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/ExperimentalPagingApi.kt @@ -0,0 +1,6 @@ +package org.mobilenativefoundation.storex.paging.runtime + +@RequiresOptIn(message = "This API is experimental. It may be changed in the future without notice.") +@Retention(AnnotationRetention.BINARY) +@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) +annotation class ExperimentalPagingApi \ No newline at end of file diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Operation.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Operation.kt index 8d38912..3a98df9 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Operation.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Operation.kt @@ -7,7 +7,7 @@ package org.mobilenativefoundation.storex.paging.runtime * @param PageRequestKey The type of the paging key. * @param ItemValue The type of the item value. */ -interface Operation { +abstract class Operation { /** * Determines whether this operation should be applied based on the current state. * @@ -16,7 +16,7 @@ interface Operation { * @param fetchingState The current fetching state. * @return True if the operation should be applied, false otherwise. */ - fun shouldApply(key: PageRequestKey?, pagingState: PagingState, fetchingState: FetchingState): Boolean + internal abstract fun shouldApply(key: PageRequestKey?, pagingState: PagingState, fetchingState: FetchingState): Boolean /** * Applies the operation to the given snapshot. @@ -27,10 +27,10 @@ interface Operation { * @param fetchingState The current fetching state. * @return The transformed snapshot after applying the operation. */ - fun apply( + internal abstract fun apply( snapshot: ItemSnapshotList, key: PageRequestKey?, - pagingState: PagingState, + pagingState: PagingState, fetchingState: FetchingState ): ItemSnapshotList } \ No newline at end of file diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/OperationPipeline.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/OperationPipeline.kt new file mode 100644 index 0000000..f2ea670 --- /dev/null +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/OperationPipeline.kt @@ -0,0 +1,3 @@ +package org.mobilenativefoundation.storex.paging.runtime + +interface OperationPipeline: List> \ No newline at end of file diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Pager.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Pager.kt index 3562ae3..c165992 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Pager.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/Pager.kt @@ -2,6 +2,6 @@ package org.mobilenativefoundation.storex.paging.runtime import kotlinx.coroutines.flow.StateFlow -interface Pager { - val state: StateFlow> +interface Pager { + val state: StateFlow> } diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/PagingScope.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/PagingScope.kt index 1ab43ab..8bfd083 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/PagingScope.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/PagingScope.kt @@ -10,34 +10,35 @@ import org.mobilenativefoundation.storex.paging.persistence.api.ItemPersistence import org.mobilenativefoundation.storex.paging.persistence.api.PagePersistence import org.mobilenativefoundation.storex.paging.runtime.internal.pagingScope.impl.PagingScopeBuilder -interface PagingScope { - fun getPager(): Pager +interface PagingScope { + fun getPager(): Pager fun getOperationManager(): OperationManager - fun getDispatcher(): Dispatcher + fun getDispatcher(): Dispatcher fun getUpdatingItemProvider(): UpdatingItemProvider - interface Builder { - fun setInitialState(state: PagingState): Builder - fun setInitialLoadParams(params: PagingSource.LoadParams): Builder - fun setPagingSource(source: PagingSource): Builder - fun setCoroutineDispatcher(dispatcher: CoroutineDispatcher): Builder - fun addLaunchEffect(effect: LaunchEffect): Builder - fun addSideEffect(effect: SideEffect): Builder - fun addMiddleware(mw: Middleware): Builder - fun setInitialFetchingState(state: FetchingState): Builder - fun setFetchingStrategy(strategy: FetchingStrategy): Builder - fun setErrorHandlingStrategy(strategy: ErrorHandlingStrategy): Builder - fun setItemMemoryCache(cache: MutableMap): Builder - fun setPageMemoryCache(cache: MutableMap>): Builder - fun setItemPersistence(persistence: ItemPersistence): Builder - fun setPagePersistence(persistence: PagePersistence): Builder - fun setItemUpdater(updater: Updater): Builder - fun setPlaceholderFactory(placeholderFactory: PlaceholderFactory): Builder - fun build(): PagingScope + interface Builder { + fun setInitialState(state: PagingState): Builder + fun setInitialLoadParams(params: PagingSource.LoadParams): Builder + fun setPagingSource(source: PagingSource): Builder + fun setCoroutineDispatcher(dispatcher: CoroutineDispatcher): Builder + fun addLaunchEffect(effect: LaunchEffect): Builder + fun addSideEffect(effect: SideEffect): Builder + fun addMiddleware(mw: Middleware): Builder + fun setInitialFetchingState(state: FetchingState): Builder + fun setFetchingStrategy(strategy: FetchingStrategy): Builder + fun setErrorHandlingStrategy(strategy: ErrorHandlingStrategy): Builder + fun setItemMemoryCache(cache: MutableMap): Builder + fun setPageMemoryCache(cache: MutableMap>): Builder + fun setItemPersistence(persistence: ItemPersistence): Builder + fun setPagePersistence(persistence: PagePersistence): Builder + fun setItemUpdater(updater: Updater): Builder + fun setPlaceholderFactory(placeholderFactory: PlaceholderFactory): Builder + fun setInitialOperations(operations: List>): Builder + fun build(): PagingScope } companion object { - fun builder( + fun builder( pagingConfig: PagingConfig ): Builder = PagingScopeBuilder(pagingConfig) } diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/PagingState.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/PagingState.kt index 850472d..f1655e8 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/PagingState.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/PagingState.kt @@ -1,14 +1,18 @@ package org.mobilenativefoundation.storex.paging.runtime +import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.MutableOperationPipeline -data class PagingState( + +data class PagingState( val ids: List, val loadStates: CombinedLoadStates, + val mutableOperationPipeline: MutableOperationPipeline ) { companion object { - fun initial() = PagingState( + fun initial() = PagingState( emptyList(), - CombinedLoadStates.initial() + CombinedLoadStates.initial(), + MutableOperationPipeline.empty() ) } } diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/api/MutableOperationPipeline.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/api/MutableOperationPipeline.kt new file mode 100644 index 0000000..ea74da9 --- /dev/null +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/api/MutableOperationPipeline.kt @@ -0,0 +1,18 @@ +package org.mobilenativefoundation.storex.paging.runtime.internal.pager.api + +import org.mobilenativefoundation.storex.paging.runtime.Operation +import org.mobilenativefoundation.storex.paging.runtime.OperationPipeline +import org.mobilenativefoundation.storex.paging.runtime.internal.pager.impl.RealMutableOperationPipeline + +interface MutableOperationPipeline : + OperationPipeline, MutableList> { + + companion object { + fun empty(): MutableOperationPipeline { + return RealMutableOperationPipeline(mutableListOf()) + } + } +} + + + diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/api/OperationApplier.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/api/OperationApplier.kt index 3da8752..afc9182 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/api/OperationApplier.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/api/OperationApplier.kt @@ -11,7 +11,7 @@ internal interface OperationApplier, key: PageRequestKey?, - pagingState: PagingState, + pagingState: PagingState, fetchingState: FetchingState ): ItemSnapshotList } \ No newline at end of file diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/api/PagingStateManager.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/api/PagingStateManager.kt index f7599f4..a3e069b 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/api/PagingStateManager.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/api/PagingStateManager.kt @@ -6,8 +6,8 @@ import org.mobilenativefoundation.storex.paging.runtime.PagingState /** * Manages the paging state and provides methods to update it. */ -internal interface PagingStateManager { - val pagingState: StateFlow> +internal interface PagingStateManager { + val pagingState: StateFlow> fun updateWithAppendData(ids: List, endOfPaginationReached: Boolean) fun updateWithPrependData(ids: List, endOfPaginationReached: Boolean) fun updateWithAppendError(error: Throwable) diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/ConcurrentOperationApplier.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/ConcurrentOperationApplier.kt index 576be89..41d47ca 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/ConcurrentOperationApplier.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/ConcurrentOperationApplier.kt @@ -7,6 +7,7 @@ import org.mobilenativefoundation.storex.paging.runtime.ItemSnapshotList import org.mobilenativefoundation.storex.paging.runtime.Operation import org.mobilenativefoundation.storex.paging.runtime.OperationManager import org.mobilenativefoundation.storex.paging.runtime.PagingState +import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.MutableOperationPipeline import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.OperationApplier /** @@ -19,8 +20,9 @@ import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.Opera * @param PageRequestKey The type of the paging key. * @param ItemValue The type of the item value. */ -class ConcurrentOperationApplier( - private val operationManager: OperationManager +class ConcurrentOperationApplier( + private val operationManager: OperationManager, + private val mutableOperationPipeline: MutableOperationPipeline ) : OperationApplier { // Mutex for ensuring thread-safe access to shared resources @@ -44,7 +46,7 @@ class ConcurrentOperationApplier, key: PageRequestKey?, - pagingState: PagingState, + pagingState: PagingState, fetchingState: FetchingState ): ItemSnapshotList = mutex.withLock { operationManager.get().fold(snapshot) { acc, operation -> @@ -68,12 +70,12 @@ class ConcurrentOperationApplier( - val operation: Operation, - val snapshot: ItemSnapshotList, - val key: K?, - val pagingState: PagingState, - val fetchingState: FetchingState + private data class CacheKey( + val operation: Operation, + val snapshot: ItemSnapshotList, + val key: PageRequestKey?, + val pagingState: PagingState, + val fetchingState: FetchingState ) } diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/DefaultFetchingStrategy.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/DefaultFetchingStrategy.kt index 4fd5241..a70e1ed 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/DefaultFetchingStrategy.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/DefaultFetchingStrategy.kt @@ -21,12 +21,12 @@ import kotlin.math.abs * @param ItemId The type of the item identifier. * @param PageRequestKey The type of the key used for loading pages. */ -class DefaultFetchingStrategy( +class DefaultFetchingStrategy( private val pagingConfig: PagingConfig, private val logger: PagingLogger, private val listSortAnalyzer: ListSortAnalyzer, private val itemIdComparator: Comparator -) : FetchingStrategy { +) : FetchingStrategy { // Thread-safe caching of the last analyzed list and its sort order private data class CachedOrder(val ids: List, val order: Order) @@ -38,7 +38,7 @@ class DefaultFetchingStrategy( */ override fun shouldFetchForward( params: PagingSource.LoadParams, - pagingState: PagingState, + pagingState: PagingState, fetchingState: FetchingState ): Boolean { return shouldFetch(pagingState, fetchingState, FetchDirection.FORWARD) @@ -49,7 +49,7 @@ class DefaultFetchingStrategy( */ override fun shouldFetchBackward( params: PagingSource.LoadParams, - pagingState: PagingState, + pagingState: PagingState, fetchingState: FetchingState ): Boolean { return shouldFetch(pagingState, fetchingState, FetchDirection.BACKWARD) @@ -60,7 +60,7 @@ class DefaultFetchingStrategy( * This method is optimized for performance and thread safety. */ private fun shouldFetch( - pagingState: PagingState, + pagingState: PagingState, fetchingState: FetchingState, fetchDirection: FetchDirection ): Boolean { @@ -129,7 +129,7 @@ class DefaultFetchingStrategy( * Inlined for performance in high-frequency calls. */ private inline fun checkFetchCondition( - pagingState: PagingState, + pagingState: PagingState, itemLoadedSoFar: ItemId?, itemAccessedSoFar: ItemId?, sortOrder: Order @@ -150,11 +150,11 @@ class DefaultFetchingStrategy( * Calculates the distance between two items. * Uses Comparator's distance method if available, otherwise falls back to index-based calculation. */ - private fun getDistance(itemLoaded: ItemId, itemAccessed: ItemId, pagingState: PagingState): Int { + private fun getDistance(itemLoaded: ItemId, itemAccessed: ItemId, pagingState: PagingState): Int { return itemIdComparator.distance(itemLoaded, itemAccessed) ?: calculateIndexDistance(itemLoaded, itemAccessed, pagingState) } - private fun calculateIndexDistance(itemLoaded: ItemId, itemAccessed: ItemId, pagingState: PagingState): Int { + private fun calculateIndexDistance(itemLoaded: ItemId, itemAccessed: ItemId, pagingState: PagingState): Int { var loadedIndex = -1 var accessedIndex = -1 @@ -181,7 +181,7 @@ class DefaultFetchingStrategy( * Inlined for performance in high-frequency calls. */ private inline fun isUnderPrefetchLimit( - pagingState: PagingState, + pagingState: PagingState, itemLoadedSoFar: ItemId, sortOrder: Order ): Boolean { diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/DefaultLoadingHandler.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/DefaultLoadingHandler.kt index 8d4e1fc..de574b9 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/DefaultLoadingHandler.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/DefaultLoadingHandler.kt @@ -22,9 +22,9 @@ import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.Retry import org.mobilenativefoundation.storex.paging.runtime.internal.store.api.NormalizedStore import org.mobilenativefoundation.storex.paging.runtime.internal.store.api.PageLoadState -internal class DefaultLoadingHandler( +internal class DefaultLoadingHandler( private val store: NormalizedStore, - private val pagingStateManager: PagingStateManager, + private val pagingStateManager: PagingStateManager, private val queueManager: QueueManager, private val fetchingStateHolder: FetchingStateHolder, private val errorHandlingStrategy: ErrorHandlingStrategy, diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealLoadingHandler.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealLoadingHandler.kt index 48bc299..ced560a 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealLoadingHandler.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealLoadingHandler.kt @@ -21,7 +21,7 @@ import org.mobilenativefoundation.storex.paging.runtime.internal.store.api.PageL */ internal class RealLoadingHandler( private val store: NormalizedStore, - private val pagingStateManager: PagingStateManager, + private val pagingStateManager: PagingStateManager, private val queueManager: QueueManager, private val fetchingStateHolder: FetchingStateHolder, private val errorHandlingStrategy: ErrorHandlingStrategy, diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealMutableOperationPipeline.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealMutableOperationPipeline.kt new file mode 100644 index 0000000..7597002 --- /dev/null +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealMutableOperationPipeline.kt @@ -0,0 +1,9 @@ +package org.mobilenativefoundation.storex.paging.runtime.internal.pager.impl + +import org.mobilenativefoundation.storex.paging.runtime.Operation +import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.MutableOperationPipeline + + +class RealMutableOperationPipeline( + private val operations: MutableList> +) : MutableOperationPipeline, MutableList> by operations \ No newline at end of file diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealPager.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealPager.kt index 4d29e0f..4355f64 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealPager.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealPager.kt @@ -33,20 +33,20 @@ import org.mobilenativefoundation.storex.paging.runtime.internal.store.api.Norma * Implementation of [Pager] that coordinates paging operations. */ -internal class RealPager( +internal class RealPager( recompositionMode: RecompositionMode, private val fetchingStateHolder: FetchingStateHolder, private val launchEffects: List, - private val fetchingStrategy: FetchingStrategy, + private val fetchingStrategy: FetchingStrategy, private val initialLoadParams: PagingSource.LoadParams, private val store: NormalizedStore, - private val actions: Flow>, + private val actions: Flow>, private val logger: PagingLogger, - private val pagingStateManager: PagingStateManager, + private val pagingStateManager: PagingStateManager, private val queueManager: QueueManager, private val loadingHandler: LoadingHandler, private val coroutineScope: CoroutineScope, -) : Pager { +) : Pager { init { @@ -56,7 +56,7 @@ internal class RealPager( handleEagerLoading() } - override val state: StateFlow> = + override val state: StateFlow> = coroutineScope.launchMolecule(recompositionMode.toCash()) { pagingState(actions) } @@ -66,7 +66,7 @@ internal class RealPager( * @param actions Flow of [Action] objects. */ @Composable - private fun pagingState(actions: Flow>): PagingState { + private fun pagingState(actions: Flow>): PagingState { val fetchingState by fetchingStateHolder.state.collectAsState() val pagingState by pagingStateManager.pagingState.collectAsState() @@ -133,7 +133,7 @@ internal class RealPager( * * @param actions Flow of paging actions. */ - private suspend fun handleActions(actions: Flow>) { + private suspend fun handleActions(actions: Flow>) { actions.distinctUntilChanged().collect { action -> logger.debug("Handling action: $action") @@ -142,6 +142,10 @@ internal class RealPager( is Action.SkipQueue -> handleSkipQueueAction(action) is Action.Enqueue -> handleEnqueueAction(action) Action.Invalidate -> handleInvalidateAction() + + is Action.AddOperation -> TODO() + Action.ClearOperations -> TODO() + is Action.RemoveOperation -> TODO() } } } @@ -266,16 +270,16 @@ internal class RealPager( */ private fun shouldFetchForward( queueElement: LoadParamsQueue.Element, - pagingState: PagingState, + pagingState: PagingState, fetchingState: FetchingState ): Boolean { val shouldFetch = queueElement.mechanism == LoadParamsQueue.Element.Mechanism.EnqueueRequest || - fetchingStrategy.shouldFetchForward( - queueElement.params, - pagingState, - fetchingState - ) + fetchingStrategy.shouldFetchForward( + queueElement.params, + pagingState, + fetchingState + ) logger.debug("Should fetch forward: $shouldFetch for key: ${queueElement.params.key}") diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealPagingStateManager.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealPagingStateManager.kt index 2f52d18..b6b9d13 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealPagingStateManager.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pager/impl/RealPagingStateManager.kt @@ -14,12 +14,12 @@ import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.Pagin /** * Implementation of PagingStateManager that manages the paging state. */ -class RealPagingStateManager( - initialState: PagingState, +class RealPagingStateManager( + initialState: PagingState, private val logger: PagingLogger, -) : PagingStateManager { +) : PagingStateManager { private val _pagingState = MutableStateFlow(initialState) - override val pagingState: StateFlow> = _pagingState.asStateFlow() + override val pagingState: StateFlow> = _pagingState.asStateFlow() override fun updateWithAppendData(ids: List, endOfPaginationReached: Boolean) { updateState("append data") { currentState -> @@ -59,7 +59,10 @@ class RealPagingStateManager( updateLoadState("prepend loading") { it.copy(prepend = LoadState.Loading) } } - private fun updateState(operation: String, update: (PagingState) -> PagingState) { + private fun updateState( + operation: String, + update: (PagingState) -> PagingState + ) { logger.debug("Updating paging state with $operation") logger.debug("Current paging state: ${pagingState.value}") diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pagingScope/impl/PagingScopeBuilder.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pagingScope/impl/PagingScopeBuilder.kt index d2e6654..3d4e49e 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pagingScope/impl/PagingScopeBuilder.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pagingScope/impl/PagingScopeBuilder.kt @@ -20,6 +20,7 @@ import org.mobilenativefoundation.storex.paging.runtime.FetchingState import org.mobilenativefoundation.storex.paging.runtime.IdExtractor import org.mobilenativefoundation.storex.paging.runtime.LoadDirection import org.mobilenativefoundation.storex.paging.runtime.LoadStrategy +import org.mobilenativefoundation.storex.paging.runtime.Operation import org.mobilenativefoundation.storex.paging.runtime.PagingConfig import org.mobilenativefoundation.storex.paging.runtime.PagingScope import org.mobilenativefoundation.storex.paging.runtime.PagingSource @@ -31,6 +32,7 @@ import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.Fetch import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.LinkedHashMapManager import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.ListSortAnalyzer import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.LoadingHandler +import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.MutableOperationPipeline import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.OperationApplier import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.PagingStateManager import org.mobilenativefoundation.storex.paging.runtime.internal.pager.api.QueueManager @@ -41,6 +43,7 @@ import org.mobilenativefoundation.storex.paging.runtime.internal.pager.impl.Defa import org.mobilenativefoundation.storex.paging.runtime.internal.pager.impl.DefaultListSortAnalyzer import org.mobilenativefoundation.storex.paging.runtime.internal.pager.impl.RealLinkedHashMapManager import org.mobilenativefoundation.storex.paging.runtime.internal.pager.impl.RealLoadingHandler +import org.mobilenativefoundation.storex.paging.runtime.internal.pager.impl.RealMutableOperationPipeline import org.mobilenativefoundation.storex.paging.runtime.internal.pager.impl.RealPager import org.mobilenativefoundation.storex.paging.runtime.internal.pager.impl.RealPagingStateManager import org.mobilenativefoundation.storex.paging.runtime.internal.pager.impl.RealQueueManager @@ -59,9 +62,9 @@ class PagingScopeBuilder( ) : PagingScope.Builder { private val logger = RealPagingLogger(pagingConfig.logging) - private val actionsFlow = MutableSharedFlow>(replay = 20) + private val actionsFlow = MutableSharedFlow>(replay = 20) - private var initialState: PagingState = PagingState.initial() + private var initialState: PagingState = PagingState.initial() private var initialLoadParams = PagingSource.LoadParams( pagingConfig.initialKey, LoadStrategy.SkipCache, @@ -78,9 +81,10 @@ class PagingScopeBuilder( private val middleware = mutableListOf>() private var initialFetchingState = FetchingState() private var listSortAnalyzer: ListSortAnalyzer = DefaultListSortAnalyzer(itemIdComparator) - private var fetchingStrategy: FetchingStrategy = + private var fetchingStrategy: FetchingStrategy = DefaultFetchingStrategy(pagingConfig, logger, listSortAnalyzer, itemIdComparator) private var errorHandlingStrategy: ErrorHandlingStrategy = ErrorHandlingStrategy.RetryLast() + private var initialOperations: MutableList> = mutableListOf() private lateinit var itemMemoryCache: MutableMap private lateinit var pageMemoryCache: MutableMap> @@ -89,7 +93,7 @@ class PagingScopeBuilder( private lateinit var itemUpdater: Updater private lateinit var placeholderFactory: PlaceholderFactory - override fun setInitialState(state: PagingState) = apply { initialState = state } + override fun setInitialState(state: PagingState) = apply { initialState = state } override fun setInitialLoadParams(params: PagingSource.LoadParams) = apply { initialLoadParams = params } @@ -103,7 +107,7 @@ class PagingScopeBuilder( override fun setInitialFetchingState(state: FetchingState) = apply { initialFetchingState = state } - override fun setFetchingStrategy(strategy: FetchingStrategy) = + override fun setFetchingStrategy(strategy: FetchingStrategy) = apply { fetchingStrategy = strategy } override fun setErrorHandlingStrategy(strategy: ErrorHandlingStrategy) = @@ -126,6 +130,11 @@ class PagingScopeBuilder( override fun setItemUpdater(updater: Updater) = apply { itemUpdater = updater } + override fun setInitialOperations(operations: List>): PagingScope.Builder = + apply { + this.initialOperations = operations.toMutableList() + } + override fun build(): PagingScope { val operationManager = ConcurrentOperationManager() val fetchingStateHolder = ConcurrentFetchingStateHolder(initialFetchingState, itemIdComparator, pageRequestKeyComparator) @@ -152,7 +161,8 @@ class PagingScopeBuilder( val pagingStateManager = RealPagingStateManager(initialState, logger) val queueManager = RealQueueManager(logger, pageRequestKeyComparator) - val operationApplier = ConcurrentOperationApplier(operationManager) + val mutableOperationPipeline = RealMutableOperationPipeline(initialOperations) + val operationApplier = ConcurrentOperationApplier(operationManager, mutableOperationPipeline) val loadingHandler = createLoadingHandler( store = store, pagingStateManager = pagingStateManager, @@ -207,7 +217,7 @@ class PagingScopeBuilder( private fun createLoadingHandler( store: NormalizedStore, - pagingStateManager: PagingStateManager, + pagingStateManager: PagingStateManager, queueManager: QueueManager, fetchingStateHolder: FetchingStateHolder, operationApplier: OperationApplier diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pagingScope/impl/RealDispatcher.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pagingScope/impl/RealDispatcher.kt index 83b4c01..7b8d8f0 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pagingScope/impl/RealDispatcher.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pagingScope/impl/RealDispatcher.kt @@ -4,10 +4,10 @@ import kotlinx.coroutines.flow.MutableSharedFlow import org.mobilenativefoundation.storex.paging.runtime.Action import org.mobilenativefoundation.storex.paging.runtime.Dispatcher -class RealDispatcher( - private val actionsFlow: MutableSharedFlow> -) : Dispatcher { - override suspend fun dispatch(action: Action) { +class RealDispatcher( + private val actionsFlow: MutableSharedFlow> +) : Dispatcher { + override suspend fun dispatch(action: Action) { actionsFlow.emit(action) } } \ No newline at end of file diff --git a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pagingScope/impl/RealPagingScope.kt b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pagingScope/impl/RealPagingScope.kt index 427af41..6525b0e 100644 --- a/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pagingScope/impl/RealPagingScope.kt +++ b/paging-runtime/src/commonMain/kotlin/org/mobilenativefoundation/storex/paging/runtime/internal/pagingScope/impl/RealPagingScope.kt @@ -6,13 +6,13 @@ import org.mobilenativefoundation.storex.paging.runtime.Pager import org.mobilenativefoundation.storex.paging.runtime.PagingScope import org.mobilenativefoundation.storex.paging.runtime.UpdatingItemProvider -class RealPagingScope( - private val pager: Pager, +class RealPagingScope( + private val pager: Pager, private val operationManager: OperationManager, - private val dispatcher: Dispatcher, + private val dispatcher: Dispatcher, private val updatingItemProvider: UpdatingItemProvider ) : PagingScope { - override fun getPager(): Pager { + override fun getPager(): Pager { return pager } @@ -20,7 +20,7 @@ class RealPagingScope( return operationManager } - override fun getDispatcher(): Dispatcher { + override fun getDispatcher(): Dispatcher { return dispatcher } diff --git a/paging-runtime/src/commonTest/kotlin/org/mobilenativefoundation/storex/paging/runtime/DefaultLoadingHandlerTest.kt b/paging-runtime/src/commonTest/kotlin/org/mobilenativefoundation/storex/paging/runtime/DefaultLoadingHandlerTest.kt index da9d635..c945a65 100644 --- a/paging-runtime/src/commonTest/kotlin/org/mobilenativefoundation/storex/paging/runtime/DefaultLoadingHandlerTest.kt +++ b/paging-runtime/src/commonTest/kotlin/org/mobilenativefoundation/storex/paging/runtime/DefaultLoadingHandlerTest.kt @@ -40,10 +40,10 @@ class DefaultLoadingHandlerTest { private val appendQueue = mock>() private val prependQueue = mock>() - private val pagingState = MutableStateFlow(PagingState.initial()) + private val pagingState = MutableStateFlow(PagingState.initial()) private val fetchingState = MutableStateFlow(FetchingState()) - private val pagingStateManager = mock> { + private val pagingStateManager = mock> { every { pagingState } returns this@DefaultLoadingHandlerTest.pagingState } private val store = mock>()