MeilCli/FoodSearch

View on GitHub
features/base/src/main/kotlin/net/meilcli/foodsearch/presenters/SearchQueryPresenter.kt

Summary

Maintainability
A
1 hr
Test Coverage
package net.meilcli.foodsearch.presenters

import android.os.Bundle
import kotlinx.coroutines.*
import net.meilcli.foodsearch.IList
import net.meilcli.foodsearch.Language
import net.meilcli.foodsearch.api.gnavi.entities.LargeCategory
import net.meilcli.foodsearch.coroutines.ioDispatcher
import net.meilcli.foodsearch.coroutines.mainDispatcher
import net.meilcli.foodsearch.services.IConfigurationService
import net.meilcli.foodsearch.services.IGnaviService
import net.meilcli.foodsearch.services.IJsonService
import net.meilcli.foodsearch.views.ISearchQueryView
import net.meilcli.foodsearch.views.IView

class SearchQueryPresenter(
    private val gnaviService: IGnaviService,
    private val jsonService: IJsonService,
    private val configurationService: IConfigurationService
) : BasePresenter(), ISearchQueryPresenter {

    companion object {

        private const val largeCategoriesStateKey = "large_categories"
        private const val languageStateKey = "language"
    }

    private val onDestroyViewContext = SupervisorJob() + mainDispatcher

    private val requestModel = gnaviService.createRestaurantRequestModel()
    private var largeCategories: IList<LargeCategory>? = null

    override fun onRestoreState(bundle: Bundle) {
        val savedLanguage = Language.values()[bundle.getInt(languageStateKey)]
        if (bundle.containsKey(largeCategoriesStateKey) && savedLanguage == configurationService.currentLanguage) {
            val bundleValue = bundle.getString(largeCategoriesStateKey) ?: return
            largeCategories = jsonService.toLargeCategoriesValue(bundleValue)
        }
    }

    override fun onCreatedView(view: IView) {
        if (view !is ISearchQueryView) return

        setUpOptions(view)
    }

    private fun setUpOptions(view: ISearchQueryView) {
        for (option in requestModel.createOptions()) {
            view.addOption(option.description, option.icon)
        }
    }

    override fun onResumeView(view: IView) {
        if (view !is ISearchQueryView) return

        if (largeCategories == null) {
            loadCategories(view)
        }
    }

    private fun loadCategories(view: ISearchQueryView) = launch(onDestroyViewContext) {
        val largeCategoriesTask = async(ioDispatcher) { gnaviService.getLargeCategories() }

        withContext(mainDispatcher) {
            try {
                view.showCategoryProgressState()

                largeCategories = largeCategoriesTask.await()

                view.clearCategory()
                largeCategories?.forEach { view.addCategory(it) }
                view.showCategorySuccessState()
            } catch (exception: Exception) {
                view.showCategoryFailedState()
                view.setCategoryFailedText(exception.message ?: "error")
            }
        }
    }

    override fun onViewClicked(view: IView, clickedViewId: Int) {
        if (view !is ISearchQueryView) return

        when (clickedViewId) {
            view.categoryFailedRetryButtonId -> loadCategories(view)
        }
    }

    override fun onSaveState(bundle: Bundle) {
        largeCategories?.also {
            bundle.putString(largeCategoriesStateKey, jsonService.toLargeCategoriesJson(it))
        }
        bundle.putInt(languageStateKey, configurationService.currentLanguage.ordinal)
    }

    override fun onDestroyView(view: IView) {
        onDestroyViewContext.cancel()
    }

    override fun onStartView(view: IView) {
    }

    override fun onPauseView(view: IView) {
    }

    override fun onStopView(view: IView) {
    }
}