All Downloads are FREE. Search and download functionalities are using the official Maven repository.

me.aartikov.sesame.loading.paged.internal.PagedLoadingLoop.kt Maven / Gradle / Ivy

package me.aartikov.sesame.loading.paged.internal

import me.aartikov.sesame.loading.paged.DataMerger
import me.aartikov.sesame.loading.paged.Page
import me.aartikov.sesame.loading.paged.PagedLoading.*
import me.aartikov.sesame.loading.paged.PagingInfo
import me.aartikov.sesame.loop.*

internal sealed class Action {
    data class LoadFirstPage(val fresh: Boolean, val reset: Boolean) : Action()
    object LoadMore : Action()
    data class Cancel(val reset: Boolean) : Action()
    data class MutateData(val transform: (List) -> List) : Action()

    data class NewPageLoaded(val page: Page) : Action()
    object EmptyPageLoaded : Action()
    data class LoadingError(val throwable: Throwable) : Action()
}

internal sealed class Effect {
    data class LoadFirstPage(val fresh: Boolean) : Effect()
    data class LoadNextPage(val pagingInfo: PagingInfo) : Effect()
    object CancelLoading : Effect()
    data class EmitEvent(val event: Event) : Effect()
}

internal typealias PagedLoadingLoop = Loop, Action, Effect>

internal class PagedLoadingReducer(
    private val dataMerger: DataMerger
) : Reducer, Action, Effect> {

    override fun reduce(state: State, action: Action): Next, Effect> = when (action) {

        is Action.LoadFirstPage -> {
            if (action.reset) {
                next(
                    State.Loading,
                    Effect.LoadFirstPage(action.fresh)
                )
            } else {
                when (state) {
                    is State.Empty -> next(
                        State.Loading,
                        Effect.LoadFirstPage(action.fresh)
                    )
                    is State.Error -> next(
                        State.Loading,
                        Effect.LoadFirstPage(action.fresh)
                    )
                    is State.Data -> when (state.status) {
                        DataStatus.Normal, DataStatus.LoadingMore, DataStatus.FullData -> next(
                            State.Data(state.pageCount, state.data, status = DataStatus.Refreshing),
                            Effect.LoadFirstPage(action.fresh)
                        )
                        else -> nothing()
                    }
                    else -> nothing()
                }
            }
        }

        is Action.LoadMore -> {
            when (state) {
                is State.Data -> when (state.status) {
                    DataStatus.Normal -> next(
                        State.Data(state.pageCount, state.data, status = DataStatus.LoadingMore),
                        Effect.LoadNextPage(PagingInfo(state.pageCount, state.data))
                    )
                    else -> nothing()
                }
                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.status) {
                        DataStatus.Refreshing, DataStatus.LoadingMore -> next(
                            State.Data(state.pageCount, state.data),
                            Effect.CancelLoading
                        )
                        else -> nothing()
                    }
                    else -> nothing()
                }
            }
        }

        is Action.NewPageLoaded -> {
            when (state) {
                is State.Loading -> next(
                    State.Data(
                        1,
                        action.page.data,
                        status = if (action.page.hasNextPage) DataStatus.Normal else DataStatus.FullData
                    )
                )
                is State.Data -> when (state.status) {
                    DataStatus.Refreshing -> next(
                        State.Data(
                            1,
                            action.page.data,
                            status = if (action.page.hasNextPage) DataStatus.Normal else DataStatus.FullData
                        )
                    )
                    DataStatus.LoadingMore -> next(
                        State.Data(
                            state.pageCount + 1,
                            dataMerger.merge(state.data, action.page.data),
                            status = if (action.page.hasNextPage) DataStatus.Normal else DataStatus.FullData
                        )
                    )
                    else -> nothing()
                }
                else -> nothing()
            }
        }

        is Action.EmptyPageLoaded -> {
            when (state) {
                is State.Loading -> next(State.Empty)
                is State.Data -> when (state.status) {
                    DataStatus.Refreshing -> next(State.Empty)
                    DataStatus.LoadingMore -> next(
                        State.Data(
                            state.pageCount,
                            state.data,
                            DataStatus.FullData
                        )
                    )
                    else -> nothing()
                }
                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.status) {
                    DataStatus.Refreshing, DataStatus.LoadingMore -> next(
                        State.Data(state.pageCount, state.data),
                        Effect.EmitEvent(Event.Error(action.throwable, state))
                    )
                    else -> nothing()
                }
                else -> nothing()
            }
        }

        is Action.MutateData -> {
            when (state) {
                is State.Data -> {
                    val newData = action.transform(state.data)
                    when {
                        newData.isNotEmpty() -> next(state.copy(data = newData))
                        state.status == DataStatus.Refreshing -> next(State.Loading)
                        else -> next(State.Empty)
                    }
                }
                else -> nothing()
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy