
me.aartikov.sesame.loading.simple.internal.LoadingLoop.kt Maven / Gradle / Ivy
package me.aartikov.sesame.loading.simple.internal
import me.aartikov.sesame.loading.simple.Loading.Event
import me.aartikov.sesame.loading.simple.Loading.State
import me.aartikov.sesame.loading.simple.isEmpty
import me.aartikov.sesame.loop.*
internal sealed class Action {
data class Load(val fresh: Boolean, val reset: Boolean) : Action()
data class Cancel(val reset: Boolean) : Action()
data class MutateData(val transform: (T) -> T) : Action()
data class DataLoaded(val data: T) : Action()
object EmptyDataLoaded : Action()
data class LoadingError(val throwable: Throwable) : Action()
data class DataObserved(val data: T) : Action()
object EmptyDataObserved : Action()
}
internal sealed class Effect {
data class Load(val fresh: Boolean) : Effect()
object CancelLoading : Effect()
data class EmitEvent(val event: Event) : Effect()
}
internal typealias LoadingLoop = Loop, Action, Effect>
internal class LoadingReducer : Reducer, Action, Effect> {
override fun reduce(state: State, action: Action): Next, Effect> = when (action) {
is Action.Load -> {
if (action.reset) {
next(
State.Loading,
Effect.Load(action.fresh)
)
} else {
when (state) {
is State.Empty -> next(
State.Loading,
Effect.Load(action.fresh)
)
is State.Data -> when (state.refreshing) {
false -> next(
State.Data(data = state.data, refreshing = true),
Effect.Load(action.fresh)
)
true -> nothing()
}
is State.Error -> next(
State.Loading,
Effect.Load(action.fresh)
)
else -> nothing()
}
}
}
is Action.Cancel -> {
if (action.reset) {
next(
State.Empty,
Effect.CancelLoading
)
} else {
when (state) {
is State.Loading -> next(
State.Empty,
Effect.CancelLoading
)
is State.Data -> when (state.refreshing) {
false -> nothing()
true -> next(
State.Data(state.data),
Effect.CancelLoading
)
}
else -> nothing()
}
}
}
is Action.DataLoaded -> {
when (state) {
is State.Loading -> next(State.Data(action.data))
is State.Data -> when (state.refreshing) {
false -> nothing()
true -> next(State.Data(action.data))
}
else -> nothing()
}
}
is Action.EmptyDataLoaded -> {
when (state) {
is State.Loading -> next(State.Empty)
is State.Data -> when (state.refreshing) {
false -> nothing()
true -> next(State.Empty)
}
else -> nothing()
}
}
is Action.LoadingError -> {
when (state) {
is State.Loading -> next(
State.Error(action.throwable),
Effect.EmitEvent(Event.Error(action.throwable, state))
)
is State.Data -> when (state.refreshing) {
false -> nothing()
true -> next(
State.Data(state.data),
Effect.EmitEvent(Event.Error(action.throwable, state))
)
}
else -> nothing()
}
}
is Action.DataObserved -> {
when (state) {
is State.Empty -> next(State.Data(action.data))
is State.Loading -> next(State.Data(action.data, refreshing = true))
is State.Data -> next(State.Data(action.data, refreshing = state.refreshing))
is State.Error -> next(State.Data(action.data))
}
}
is Action.EmptyDataObserved -> {
when (state) {
is State.Data -> when (state.refreshing) {
false -> next(State.Empty)
true -> next(State.Loading)
}
else -> nothing()
}
}
is Action.MutateData -> when (state) {
is State.Data -> {
val newData = action.transform(state.data)
when {
!isEmpty(newData) -> next(state.copy(data = newData))
state.refreshing -> next(State.Loading)
else -> next(State.Empty)
}
}
else -> nothing()
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy