Skip to content

Instantly share code, notes, and snippets.

@almozavr
Created October 8, 2021 13:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save almozavr/28bbca9452dd5933eae4f35848ce84e4 to your computer and use it in GitHub Desktop.
Save almozavr/28bbca9452dd5933eae4f35848ce84e4 to your computer and use it in GitHub Desktop.
Link ContainerHost intent capabilities with the Paging library
package com.example.paging
import androidx.paging.PagingSource
import androidx.paging.PagingState
import org.orbitmvi.orbit.ContainerHost
import org.orbitmvi.orbit.syntax.simple.SimpleSyntax
import org.orbitmvi.orbit.syntax.simple.intent
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
/**
* Proxy [PagingSource] that delegates calls to the actual source
* which is created at the moment of load. The calls are delegated only if actual source creation succeeds.
*/
class DelegatingPagingSource<K : Any, V : Any>(
private val producer: PagingSourceProducer<K, V>
) : PagingSource<K, V>() {
private var actualSource: PagingSource<K, V>? = null
override fun getRefreshKey(state: PagingState<K, V>): K? =
actualSource?.getRefreshKey(state)
override suspend fun load(params: LoadParams<K>): LoadResult<K, V> {
if (actualSource == null) {
actualSource = producer.invoke(params)
}
return actualSource?.load(params) ?: LoadResult.Error(IllegalStateException("Can't create actual source"))
}
companion object {
fun <K : Any, V : Any> create(producer: PagingSourceProducer<K, V>) = DelegatingPagingSource(producer)
}
}
private typealias PagingSourceProducer<K, V> = suspend (PagingSource.LoadParams<K>) -> PagingSource<K, V>?
/**
* Create [DelegatingPagingSource] with [producer] wrapped in the [ContainerHost.intent] call
*/
fun <S : Any, E : Any, K : Any, V : Any> ContainerHost<S, E>.createPagingSource(
producer: ContainerPagingSourceProducer<S, E, K, V>
) =
DelegatingPagingSource.create<K, V> { params ->
return@create suspendCoroutine { continuation ->
intent {
try {
val pagingSource = producer(this, params)
continuation.resume(pagingSource)
} catch (e: Exception) {
continuation.resumeWithException(e)
}
}
}
}
private typealias ContainerPagingSourceProducer<S, E, K, V> =
suspend SimpleSyntax<S, E>.(params: PagingSource.LoadParams<K>) -> PagingSource<K, V>?
package com.example.myitems
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import androidx.paging.PagingState
import androidx.paging.cachedIn
import androidx.paging.map
import com.example.paging.createPagingSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import org.orbitmvi.orbit.Container
import org.orbitmvi.orbit.ContainerHost
import org.orbitmvi.orbit.syntax.simple.intent
import org.orbitmvi.orbit.syntax.simple.postSideEffect
import org.orbitmvi.orbit.syntax.simple.reduce
import org.orbitmvi.orbit.viewmodel.container
class MyItemsViewModel(
savedStateHandle: SavedStateHandle,
exceptionHandler: ExceptionHandler,
private val getMyValuableDataUseCase: GetMyValuableDataUseCase,
) : ViewModel(), ContainerHost<MyItemsState, MyItemsEffect> {
override val container: Container<MyItemsState, MyItemsEffect> = container(
initialState = MyItemsState(
myValuableData = null,
),
savedStateHandle = savedStateHandle,
)
val myItems: Flow<PagingData<MyItem>> = Pager(
config = PagingConfig(
pageSize = 10,
enablePlaceholders = false,
)
) {
createMyItemPagingSource()
}.flow.map { pagingData ->
pagingData.map { it.asPresentation() }
}.cachedIn(viewModelScope)
private fun createMyItemPagingSource(): PagingSource<Int, MyItem> = createPagingSource {
val valuableData = state.myValuableData
if (valuableData == null) {
val newValuableData = getMyValuableDataUseCase()
reduce {
state.copy(myValuableData = newValuableData)
}
return@createPagingSource createActualMyItemPagingSource(newValuableData)
} else {
return@createPagingSource createActualMyItemPagingSource(valuableData)
}
return@createPagingSource null
}
private fun createActualMyItemPagingSource(valuableData: ValuableData): PagingSource<Int, MyItem> = TODO()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment