Skip to content

Commit

Permalink
Draft StatefulMarket
Browse files Browse the repository at this point in the history
Signed-off-by: Matt Ramotar <[email protected]>
  • Loading branch information
matt-ramotar committed May 4, 2024
1 parent dd6458c commit 8514305
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 3 deletions.
1 change: 1 addition & 0 deletions experimental/market/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ kotlin {
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines.core)
api(project(":store"))
api(project(":experimental:paging"))
api(libs.kotlinx.datetime)
api(libs.kotlinx.serialization.core)
api(libs.kotlinx.serialization.json)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.mobilenativefoundation.market

import kotlinx.coroutines.flow.StateFlow

interface Market<S: Market.State> {
interface Market<S : Market.State> {

val state: StateFlow<S>

Expand All @@ -18,7 +18,7 @@ interface Market<S: Market.State> {
fun dispatch(action: A)
}

fun interface Selector<S: State, R: Any> {
fun interface Selector<S : State, R : Any> {
fun select(state: S): R
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.mobilenativefoundation.market

import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import org.mobilenativefoundation.storex.paging.Identifiable
import org.mobilenativefoundation.storex.paging.Pager
import org.mobilenativefoundation.storex.paging.PagerBuilder
import org.mobilenativefoundation.storex.paging.StoreX


interface MarketPager<Id : Comparable<Id>> {

fun contribute(anchorPosition: Flow<Id>)

companion object {
fun <Id : Comparable<Id>, K : Any, V : Identifiable<Id>, E : Any, A : Market.Action, D : Market.Dispatcher<A>> from(
coroutineDispatcher: CoroutineDispatcher,
marketDispatcher: D,
actionFactory: (state: StoreX.Paging.State<Id, K, V, E>) -> A,
pagerBuilder: PagerBuilder<Id, K, V, E>.() -> Pager<Id, K, V, E>
): MarketPager<Id> {
return RealMarketPager(
coroutineDispatcher, pagerBuilder(PagerBuilder(coroutineDispatcher)), marketDispatcher, actionFactory
)
}
}
}

class RealMarketPager<Id : Comparable<Id>, K : Any, V : Identifiable<Id>, E : Any, A : Market.Action, D : Market.Dispatcher<A>>(
coroutineDispatcher: CoroutineDispatcher,
private val pager: Pager<Id, K, V, E>,
private val marketDispatcher: D,
private val actionFactory: (state: StoreX.Paging.State<Id, K, V, E>) -> A
) : MarketPager<Id> {

private val coroutineScope = CoroutineScope(coroutineDispatcher)

override fun contribute(anchorPosition: Flow<Id>) {
coroutineScope.launch {

pager(anchorPosition)
pager.flow.collect {
val action = actionFactory(it)
marketDispatcher.dispatch(action)
}
}
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.mobilenativefoundation.market


class MemoizedSelector<S : Market.State, P : Any, R : Any>(
private class MemoizedSelector<S : Market.State, P : Any, R : Any>(
private val selector: (S) -> R,
private val getParams: (S) -> P,
private val areParamsEqual: (P, P) -> Boolean = { p1, p2 -> p1 == p2 },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package org.mobilenativefoundation.market

import org.mobilenativefoundation.storex.paging.Identifiable

interface StatefulMarket<Id : Comparable<Id>, K : Any, V : Identifiable<Id>, E : Any, S : StatefulMarket.State<Id, K, V, E>> :
Market<S> {

interface State<Id : Comparable<Id>, K : Any, V : Identifiable<Id>, E : Any> : Market.State {
val subStates: Map<String, SubState<Id, K, V, E>>
}

sealed interface SubState<Id : Comparable<Id>, K : Any, V : Identifiable<Id>, E : Any>

data class NormalizedState<Id : Comparable<Id>, K : Any, V : Identifiable<Id>, E : Any>(
val allIds: List<Id>,
val byId: Map<Id, ItemState<Id, K, V, E>>
) : SubState<Id, K, V, E>


sealed interface ItemState<Id : Comparable<Id>, K : Any, V : Identifiable<Id>, E : Any> {
data object Initial : ItemState<Nothing, Nothing, Nothing, Nothing>
data object Loading : ItemState<Nothing, Nothing, Nothing, Nothing>
data class Error<E : Any>(val error: E) : ItemState<Nothing, Nothing, Nothing, E>
data class Data<Id : Comparable<Id>, V : Identifiable<Id>>(
val value: V,
val status: Status,
val lastModified: Long,
val lastRefreshed: Long,
) : SubState<Id, Nothing, V, Nothing> {
enum class Status {
Idle,
Downloading,
Uploading,
}
}
}


sealed interface PagingState<Id : Comparable<Id>, K : Any, V : Identifiable<Id>, E : Any> : SubState<Id, K, V, E> {
val anchorPosition: Id?
val prefetchPosition: Id?

data class Initial<Id : Comparable<Id>, K : Any, V : Identifiable<Id>, E : Any>(
override val prefetchPosition: Id?,
override val anchorPosition: Id?,
) : PagingState<Id, K, V, E>

data class Loading<Id : Comparable<Id>, K : Any, V : Identifiable<Id>, E : Any>(
override val prefetchPosition: Id?,
override val anchorPosition: Id?,
) : PagingState<Id, K, V, E>

data class Error<Id : Comparable<Id>, K : Any, V : Identifiable<Id>, E : Any>(
val value: E,
override val prefetchPosition: Id?,
override val anchorPosition: Id?,
) : PagingState<Id, K, V, E>

data class Data<Id : Comparable<Id>, K : Any, V : Identifiable<Id>, E : Any>(
val allIds: List<Id>,
override val anchorPosition: Id?,
override val prefetchPosition: Id?,
val lastModified: Long,
val lastRefreshed: Long,
val status: Status
) : PagingState<Id, K, V, E> {
enum class Status {
Idle,
LoadingMore,
ErrorLoadingMore,
Refreshing
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ internal class RealMarketSupplier<K : Any, O : Any, A : Market.Action, D : Marke
fun interface MarketActionFactory<O : Any, A : Market.Action> {
fun create(storeOutput: O): A
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package monster.scoop.xplat.domain.story.api

import monster.scoop.xplat.foundation.networking.api.GetStoryQuery
import org.mobilenativefoundation.market.MarketSupplier

typealias StorySupplier = MarketSupplier<GetStoryQuery>

0 comments on commit 8514305

Please sign in to comment.