-
Notifications
You must be signed in to change notification settings - Fork 202
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: mramotar <mramotar@dropbox.com>
- Loading branch information
1 parent
5575a0b
commit cf30814
Showing
11 changed files
with
421 additions
and
0 deletions.
There are no files selected for viewing
30 changes: 30 additions & 0 deletions
30
...ore/src/commonMain/kotlin/org/mobilenativefoundation/paging/core/PagingSourceCollector.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package org.mobilenativefoundation.paging.core | ||
|
||
import kotlinx.coroutines.flow.Flow | ||
|
||
/** | ||
* Represents a collector for [PagingSource.LoadResult] objects. | ||
* | ||
* @param Id The type of the unique identifier for each item in the paged data. | ||
* @param K The type of the key used for paging. | ||
* @param P The type of the parameters associated with each page of data. | ||
* @param D The type of the data items. | ||
* @param E The type of errors that can occur during the paging process. | ||
* @param A The type of custom actions that can be dispatched. | ||
*/ | ||
interface PagingSourceCollector<Id : Comparable<Id>, K : Any, P : Any, D : Any, E : Any, A : Any> { | ||
/** | ||
* Collects the load results from the [PagingSource] and dispatches appropriate [PagingAction] objects. | ||
* | ||
* @param params The [PagingSource.LoadParams] associated with the load operation. | ||
* @param results The flow of [PagingSource.LoadResult] instances representing the load results. | ||
* @param state The current [PagingState] when collecting the load results. | ||
* @param dispatch The function to dispatch [PagingAction] instances based on the load results. | ||
*/ | ||
suspend operator fun invoke( | ||
params: PagingSource.LoadParams<K, P>, | ||
results: Flow<PagingSource.LoadResult<Id, K, P, D, E>>, | ||
state: PagingState<Id, K, P, D, E>, | ||
dispatch: (action: PagingAction<Id, K, P, D, E, A>) -> Unit | ||
) | ||
} |
22 changes: 22 additions & 0 deletions
22
...rc/commonMain/kotlin/org/mobilenativefoundation/paging/core/PagingSourceStreamProvider.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package org.mobilenativefoundation.paging.core | ||
|
||
import kotlinx.coroutines.flow.Flow | ||
|
||
/** | ||
* Represents a provider of [PagingSource.LoadResult] streams. | ||
* | ||
* @param Id The type of the unique identifier for each item in the paged data. | ||
* @param K The type of the key used for paging. | ||
* @param P The type of the parameters associated with each page of data. | ||
* @param D The type of the data items. | ||
* @param E The type of errors that can occur during the paging process. | ||
*/ | ||
interface PagingSourceStreamProvider<Id : Comparable<Id>, K : Any, P : Any, D : Any, E : Any> { | ||
/** | ||
* Provides a flow of [PagingSource.LoadResult] instances for the specified [PagingSource.LoadParams]. | ||
* | ||
* @param params The [PagingSource.LoadParams] for which to provide the load result stream. | ||
* @return A flow of [PagingSource.LoadResult] instances representing the load results. | ||
*/ | ||
fun provide(params: PagingSource.LoadParams<K, P>): Flow<PagingSource.LoadResult<Id, K, P, D, E>> | ||
} |
5 changes: 5 additions & 0 deletions
5
...c/commonMain/kotlin/org/mobilenativefoundation/paging/core/StorePagingSourceKeyFactory.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package org.mobilenativefoundation.paging.core | ||
|
||
fun interface StorePagingSourceKeyFactory<Id : Comparable<Id>, K : Any, P : Any, D : Any> { | ||
fun createKeyFor(single: PagingData.Single<Id, K, P, D>): PagingKey<K, P> | ||
} |
49 changes: 49 additions & 0 deletions
49
paging/core/src/commonMain/kotlin/org/mobilenativefoundation/paging/core/effects.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package org.mobilenativefoundation.paging.core | ||
|
||
/** | ||
* A type alias for an [Effect] that loads the next page of data when the paging state is [PagingState.Data.Idle]. | ||
* | ||
* @param Id The type of the unique identifier for each item in the paged data. | ||
* @param K The type of the key used for paging. | ||
* @param P The type of the parameters associated with each page of data. | ||
* @param D The type of the data items. | ||
* @param E The type of errors that can occur during the paging process. | ||
* @param A The type of custom actions that can be dispatched. | ||
*/ | ||
typealias LoadNextEffect<Id, K, P, D, E, A> = Effect<Id, K, P, D, E, A, PagingAction.UpdateData<Id, K, P, D, E, A>, PagingState.Data.Idle<Id, K, P, D, E>> | ||
|
||
/** | ||
* A type alias for an [Effect] that loads data when a [PagingAction.Load] action is dispatched and the paging state is [PagingState]. | ||
* | ||
* @param Id The type of the unique identifier for each item in the paged data. | ||
* @param K The type of the key used for paging. | ||
* @param P The type of the parameters associated with each page of data. | ||
* @param D The type of the data items. | ||
* @param E The type of errors that can occur during the paging process. | ||
* @param A The type of custom actions that can be dispatched to modify the paging state. | ||
*/ | ||
typealias AppLoadEffect<Id, K, P, D, E, A> = Effect<Id, K, P, D, E, A, PagingAction.Load<Id, K, P, D, E, A>, PagingState<Id, K, P, D, E>> | ||
|
||
/** | ||
* A type alias for an [Effect] that loads data when a [PagingAction.User.Load] action is dispatched and the paging state is [PagingState.Loading]. | ||
* | ||
* @param Id The type of the unique identifier for each item in the paged data. | ||
* @param K The type of the key used for paging. | ||
* @param P The type of the parameters associated with each page of data. | ||
* @param D The type of the data items. | ||
* @param E The type of errors that can occur during the paging process. | ||
* @param A The type of custom actions that can be dispatched to modify the paging state. | ||
*/ | ||
typealias UserLoadEffect<Id, K, P, D, E, A> = Effect<Id, K, P, D, E, A, PagingAction.User.Load<Id, K, P, D, E, A>, PagingState.Loading<Id, K, P, D, E>> | ||
|
||
/** | ||
* A type alias for an [Effect] that loads more data when a [PagingAction.User.Load] action is dispatched and the paging state is [PagingState.Data.LoadingMore]. | ||
* | ||
* @param Id The type of the unique identifier for each item in the paged data. | ||
* @param K The type of the key used for paging. | ||
* @param P The type of the parameters associated with each page of data. | ||
* @param D The type of the data items. | ||
* @param E The type of errors that can occur during the paging process. | ||
* @param A The type of custom actions that can be dispatched to modify the paging state. | ||
*/ | ||
typealias UserLoadMoreEffect<Id, K, P, D, E, A> = Effect<Id, K, P, D, E, A, PagingAction.User.Load<Id, K, P, D, E, A>, PagingState.Data.LoadingMore<Id, K, P, D, E>> |
43 changes: 43 additions & 0 deletions
43
...src/commonMain/kotlin/org/mobilenativefoundation/paging/core/impl/DefaultAppLoadEffect.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package org.mobilenativefoundation.paging.core.impl | ||
|
||
import org.mobilenativefoundation.paging.core.AppLoadEffect | ||
import org.mobilenativefoundation.paging.core.Logger | ||
import org.mobilenativefoundation.paging.core.PagingAction | ||
import org.mobilenativefoundation.paging.core.PagingSource | ||
import org.mobilenativefoundation.paging.core.PagingSourceCollector | ||
import org.mobilenativefoundation.paging.core.PagingState | ||
|
||
class DefaultAppLoadEffect<Id : Comparable<Id>, K : Any, P : Any, D : Any, E : Any, A : Any>( | ||
loggerInjector: OptionalInjector<Logger>, | ||
dispatcherInjector: Injector<Dispatcher<Id, K, P, D, E, A>>, | ||
pagingSourceCollectorInjector: Injector<PagingSourceCollector<Id, K, P, D, E, A>>, | ||
pagingSourceInjector: Injector<PagingSource<Id, K, P, D, E>>, | ||
private val jobCoordinator: JobCoordinator, | ||
private val stateManager: StateManager<Id, K, P, D, E>, | ||
) : AppLoadEffect<Id, K, P, D, E, A> { | ||
private val logger = lazy { loggerInjector.inject() } | ||
private val dispatcher = lazy { dispatcherInjector.inject() } | ||
private val pagingSourceCollector = lazy { pagingSourceCollectorInjector.inject() } | ||
private val pagingSource = lazy { pagingSourceInjector.inject() } | ||
|
||
override fun invoke(action: PagingAction.Load<Id, K, P, D, E, A>, state: PagingState<Id, K, P, D, E>, dispatch: (PagingAction<Id, K, P, D, E, A>) -> Unit) { | ||
logger.value?.log( | ||
"""Running post reducer effect: | ||
Effect: App load | ||
State: $state | ||
Action: $action | ||
""".trimIndent(), | ||
) | ||
|
||
jobCoordinator.launchIfNotActive(action.key) { | ||
val params = PagingSource.LoadParams(action.key, true) | ||
pagingSourceCollector.value( | ||
params, | ||
pagingSource.value.stream(params), | ||
stateManager.state.value, | ||
dispatcher.value::dispatch | ||
) | ||
} | ||
} | ||
|
||
} |
30 changes: 30 additions & 0 deletions
30
...rc/commonMain/kotlin/org/mobilenativefoundation/paging/core/impl/DefaultLoadNextEffect.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package org.mobilenativefoundation.paging.core.impl | ||
|
||
import org.mobilenativefoundation.paging.core.LoadNextEffect | ||
import org.mobilenativefoundation.paging.core.Logger | ||
import org.mobilenativefoundation.paging.core.PagingAction | ||
import org.mobilenativefoundation.paging.core.PagingState | ||
|
||
class DefaultLoadNextEffect<Id : Comparable<Id>, K : Any, P : Any, D : Any, E : Any, A : Any>( | ||
loggerInjector: OptionalInjector<Logger>, | ||
queueManagerInjector: Injector<QueueManager<K, P>>, | ||
) : LoadNextEffect<Id, K, P, D, E, A> { | ||
|
||
private val logger = lazy { loggerInjector.inject() } | ||
private val queueManager = lazy { queueManagerInjector.inject() } | ||
|
||
override fun invoke(action: PagingAction.UpdateData<Id, K, P, D, E, A>, state: PagingState.Data.Idle<Id, K, P, D, E>, dispatch: (PagingAction<Id, K, P, D, E, A>) -> Unit) { | ||
logger.value?.log( | ||
""" | ||
Running post reducer effect: | ||
Effect: Load next | ||
State: $state | ||
Action: $action | ||
""".trimIndent(), | ||
) | ||
|
||
action.data.collection.nextKey?.key?.let { | ||
queueManager.value.enqueue(action.data.collection.nextKey) | ||
} | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
...onMain/kotlin/org/mobilenativefoundation/paging/core/impl/DefaultPagingSourceCollector.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package org.mobilenativefoundation.paging.core.impl | ||
|
||
import kotlinx.coroutines.flow.Flow | ||
import org.mobilenativefoundation.paging.core.PagingAction | ||
import org.mobilenativefoundation.paging.core.PagingSource | ||
import org.mobilenativefoundation.paging.core.PagingSourceCollector | ||
import org.mobilenativefoundation.paging.core.PagingState | ||
|
||
class DefaultPagingSourceCollector<Id : Comparable<Id>, K : Any, P : Any, D : Any, E : Any, A : Any> : PagingSourceCollector<Id, K, P, D, E, A> { | ||
override suspend fun invoke( | ||
params: PagingSource.LoadParams<K, P>, | ||
results: Flow<PagingSource.LoadResult<Id, K, P, D, E>>, | ||
state: PagingState<Id, K, P, D, E>, | ||
dispatch: (action: PagingAction<Id, K, P, D, E, A>) -> Unit | ||
) { | ||
results.collect { result -> | ||
when (result) { | ||
is PagingSource.LoadResult.Data -> dispatch(PagingAction.UpdateData(params, result)) | ||
is PagingSource.LoadResult.Error -> dispatch(PagingAction.UpdateError(params, result)) | ||
} | ||
} | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
...rc/commonMain/kotlin/org/mobilenativefoundation/paging/core/impl/DefaultUserLoadEffect.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package org.mobilenativefoundation.paging.core.impl | ||
|
||
import org.mobilenativefoundation.paging.core.Logger | ||
import org.mobilenativefoundation.paging.core.PagingAction | ||
import org.mobilenativefoundation.paging.core.PagingSource | ||
import org.mobilenativefoundation.paging.core.PagingSourceCollector | ||
import org.mobilenativefoundation.paging.core.PagingState | ||
import org.mobilenativefoundation.paging.core.UserLoadEffect | ||
|
||
class DefaultUserLoadEffect<Id : Comparable<Id>, K : Any, P : Any, D : Any, E : Any, A : Any>( | ||
loggerInjector: OptionalInjector<Logger>, | ||
dispatcherInjector: Injector<Dispatcher<Id, K, P, D, E, A>>, | ||
pagingSourceCollectorInjector: Injector<PagingSourceCollector<Id, K, P, D, E, A>>, | ||
pagingSourceInjector: Injector<PagingSource<Id, K, P, D, E>>, | ||
private val jobCoordinator: JobCoordinator, | ||
private val stateManager: StateManager<Id, K, P, D, E>, | ||
) : UserLoadEffect<Id, K, P, D, E, A> { | ||
private val logger = lazy { loggerInjector.inject() } | ||
private val dispatcher = lazy { dispatcherInjector.inject() } | ||
private val pagingSourceCollector = lazy { pagingSourceCollectorInjector.inject() } | ||
private val pagingSource = lazy { pagingSourceInjector.inject() } | ||
|
||
override fun invoke(action: PagingAction.User.Load<Id, K, P, D, E, A>, state: PagingState.Loading<Id, K, P, D, E>, dispatch: (PagingAction<Id, K, P, D, E, A>) -> Unit) { | ||
logger.value?.log( | ||
"""Running post reducer effect: | ||
Effect: User load | ||
State: $state | ||
Action: $action | ||
""".trimIndent(), | ||
) | ||
|
||
jobCoordinator.launch(action.key) { | ||
val params = PagingSource.LoadParams(action.key, true) | ||
pagingSourceCollector.value( | ||
params, | ||
pagingSource.value.stream(params), | ||
stateManager.state.value, | ||
dispatcher.value::dispatch | ||
) | ||
} | ||
} | ||
|
||
} |
43 changes: 43 additions & 0 deletions
43
...ommonMain/kotlin/org/mobilenativefoundation/paging/core/impl/DefaultUserLoadMoreEffect.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package org.mobilenativefoundation.paging.core.impl | ||
|
||
import org.mobilenativefoundation.paging.core.Logger | ||
import org.mobilenativefoundation.paging.core.PagingAction | ||
import org.mobilenativefoundation.paging.core.PagingSource | ||
import org.mobilenativefoundation.paging.core.PagingSourceCollector | ||
import org.mobilenativefoundation.paging.core.PagingState | ||
import org.mobilenativefoundation.paging.core.UserLoadMoreEffect | ||
|
||
class DefaultUserLoadMoreEffect<Id : Comparable<Id>, K : Any, P : Any, D : Any, E : Any, A : Any>( | ||
loggerInjector: OptionalInjector<Logger>, | ||
dispatcherInjector: Injector<Dispatcher<Id, K, P, D, E, A>>, | ||
pagingSourceCollectorInjector: Injector<PagingSourceCollector<Id, K, P, D, E, A>>, | ||
pagingSourceInjector: Injector<PagingSource<Id, K, P, D, E>>, | ||
private val jobCoordinator: JobCoordinator, | ||
private val stateManager: StateManager<Id, K, P, D, E>, | ||
) : UserLoadMoreEffect<Id, K, P, D, E, A> { | ||
private val logger = lazy { loggerInjector.inject() } | ||
private val dispatcher = lazy { dispatcherInjector.inject() } | ||
private val pagingSourceCollector = lazy { pagingSourceCollectorInjector.inject() } | ||
private val pagingSource = lazy { pagingSourceInjector.inject() } | ||
|
||
override fun invoke(action: PagingAction.User.Load<Id, K, P, D, E, A>, state: PagingState.Data.LoadingMore<Id, K, P, D, E>, dispatch: (PagingAction<Id, K, P, D, E, A>) -> Unit) { | ||
logger.value?.log( | ||
"""Running post reducer effect: | ||
Effect: User load more | ||
State: $state | ||
Action: $action | ||
""".trimIndent(), | ||
) | ||
|
||
jobCoordinator.launch(action.key) { | ||
val params = PagingSource.LoadParams(action.key, true) | ||
pagingSourceCollector.value( | ||
params, | ||
pagingSource.value.stream(params), | ||
stateManager.state.value, | ||
dispatcher.value::dispatch | ||
) | ||
} | ||
} | ||
|
||
} |
78 changes: 78 additions & 0 deletions
78
...ain/kotlin/org/mobilenativefoundation/paging/core/impl/StorePagingSourceStreamProvider.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package org.mobilenativefoundation.paging.core.impl | ||
|
||
import kotlinx.coroutines.flow.Flow | ||
import kotlinx.coroutines.flow.distinctUntilChanged | ||
import kotlinx.coroutines.flow.map | ||
import kotlinx.coroutines.flow.onEach | ||
import kotlinx.coroutines.sync.Mutex | ||
import kotlinx.coroutines.sync.withLock | ||
import org.mobilenativefoundation.paging.core.PagingData | ||
import org.mobilenativefoundation.paging.core.PagingKey | ||
import org.mobilenativefoundation.paging.core.PagingSource | ||
import org.mobilenativefoundation.paging.core.PagingSourceStreamProvider | ||
import org.mobilenativefoundation.paging.core.StorePagingSourceKeyFactory | ||
import org.mobilenativefoundation.store.store5.StoreReadResponse | ||
|
||
class StorePagingSourceStreamProvider<Id : Comparable<Id>, K : Any, P : Any, D : Any, E : Any>( | ||
private val createParentStream: (key: PagingKey<K, P>) -> Flow<PagingSource.LoadResult<Id, K, P, D, E>>, | ||
private val createChildStream: (key: PagingKey<K, P>) -> Flow<StoreReadResponse<PagingData<Id, K, P, D>>>, | ||
private val keyFactory: StorePagingSourceKeyFactory<Id, K, P, D> | ||
) : PagingSourceStreamProvider<Id, K, P, D, E> { | ||
private val pages: MutableMap<PagingKey<K, P>, PagingSource.LoadResult.Data<Id, K, P, D>> = mutableMapOf() | ||
private val mutexForPages = Mutex() | ||
|
||
override fun provide(params: PagingSource.LoadParams<K, P>): Flow<PagingSource.LoadResult<Id, K, P, D, E>> = | ||
createParentStream(params.key).map { result -> | ||
when (result) { | ||
is PagingSource.LoadResult.Data -> { | ||
mutexForPages.withLock { | ||
pages[params.key] = result | ||
} | ||
|
||
var data = result | ||
|
||
result.collection.items.forEach { child -> | ||
val childKey = keyFactory.createKeyFor(child) | ||
initAndCollectChildStream(child, childKey, params.key) { updatedData -> data = updatedData } | ||
} | ||
|
||
data | ||
} | ||
|
||
is PagingSource.LoadResult.Error -> result | ||
} | ||
} | ||
|
||
private fun initAndCollectChildStream( | ||
data: PagingData.Single<Id, K, P, D>, | ||
key: PagingKey<K, P>, | ||
parentKey: PagingKey<K, P>, | ||
emit: (updatedData: PagingSource.LoadResult.Data<Id, K, P, D>) -> Unit | ||
) { | ||
createChildStream(key).distinctUntilChanged().onEach { response -> | ||
|
||
if (response is StoreReadResponse.Data) { | ||
val updatedValue = response.value | ||
|
||
if (updatedValue is PagingData.Single) { | ||
mutexForPages.withLock { | ||
pages[parentKey]!!.let { currentData -> | ||
val updatedItems = currentData.collection.items.toMutableList() | ||
val indexOfChild = updatedItems.indexOfFirst { it.id == data.id } | ||
val child = updatedItems[indexOfChild] | ||
if (child != updatedValue) { | ||
updatedItems[indexOfChild] = updatedValue | ||
|
||
val updatedPage = currentData.copy(collection = currentData.collection.copy(items = updatedItems)) | ||
|
||
pages[parentKey] = updatedPage | ||
|
||
emit(updatedPage) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.