Merge pull request #93 from kirmanak/recipe-loading-experience
Refresh recipes on authorization
This commit is contained in:
@@ -15,4 +15,6 @@ interface RecipeRepo {
|
|||||||
suspend fun loadRecipeInfo(recipeId: String): FullRecipeEntity?
|
suspend fun loadRecipeInfo(recipeId: String): FullRecipeEntity?
|
||||||
|
|
||||||
fun updateNameQuery(name: String?)
|
fun updateNameQuery(name: String?)
|
||||||
|
|
||||||
|
suspend fun refreshRecipes()
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,11 @@ class RecipeRepoImpl @Inject constructor(
|
|||||||
|
|
||||||
override fun createPager(): Pager<Int, RecipeSummaryEntity> {
|
override fun createPager(): Pager<Int, RecipeSummaryEntity> {
|
||||||
logger.v { "createPager() called" }
|
logger.v { "createPager() called" }
|
||||||
val pagingConfig = PagingConfig(pageSize = 5, enablePlaceholders = true)
|
val pagingConfig = PagingConfig(
|
||||||
|
pageSize = LOAD_PAGE_SIZE,
|
||||||
|
enablePlaceholders = true,
|
||||||
|
initialLoadSize = INITIAL_LOAD_PAGE_SIZE,
|
||||||
|
)
|
||||||
return Pager(
|
return Pager(
|
||||||
config = pagingConfig,
|
config = pagingConfig,
|
||||||
remoteMediator = mediator,
|
remoteMediator = mediator,
|
||||||
@@ -58,4 +62,18 @@ class RecipeRepoImpl @Inject constructor(
|
|||||||
logger.v { "updateNameQuery() called with: name = $name" }
|
logger.v { "updateNameQuery() called with: name = $name" }
|
||||||
pagingSourceFactory.setQuery(name)
|
pagingSourceFactory.setQuery(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun refreshRecipes() {
|
||||||
|
logger.v { "refreshRecipes() called" }
|
||||||
|
runCatchingExceptCancel {
|
||||||
|
storage.refreshAll(dataSource.requestRecipes(0, INITIAL_LOAD_PAGE_SIZE))
|
||||||
|
}.onFailure {
|
||||||
|
logger.e(it) { "Can't refresh recipes" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val LOAD_PAGE_SIZE = 50
|
||||||
|
private const val INITIAL_LOAD_PAGE_SIZE = LOAD_PAGE_SIZE * 3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,10 @@ import by.kirich1409.viewbindingdelegate.viewBinding
|
|||||||
import com.google.android.material.shape.CornerFamily
|
import com.google.android.material.shape.CornerFamily
|
||||||
import com.google.android.material.shape.MaterialShapeDrawable
|
import com.google.android.material.shape.MaterialShapeDrawable
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import gq.kirmanak.mealient.NavGraphDirections
|
import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalAddRecipeFragment
|
||||||
|
import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalAuthenticationFragment
|
||||||
|
import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalBaseURLFragment
|
||||||
|
import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalRecipesListFragment
|
||||||
import gq.kirmanak.mealient.R
|
import gq.kirmanak.mealient.R
|
||||||
import gq.kirmanak.mealient.databinding.MainActivityBinding
|
import gq.kirmanak.mealient.databinding.MainActivityBinding
|
||||||
import gq.kirmanak.mealient.extensions.observeOnce
|
import gq.kirmanak.mealient.extensions.observeOnce
|
||||||
@@ -69,9 +72,9 @@ class MainActivity : AppCompatActivity(R.layout.main_activity) {
|
|||||||
logger.v { "onNavigationItemSelected() called with: menuItem = $menuItem" }
|
logger.v { "onNavigationItemSelected() called with: menuItem = $menuItem" }
|
||||||
menuItem.isChecked = true
|
menuItem.isChecked = true
|
||||||
val directions = when (menuItem.itemId) {
|
val directions = when (menuItem.itemId) {
|
||||||
R.id.add_recipe -> NavGraphDirections.actionGlobalAddRecipeFragment()
|
R.id.add_recipe -> actionGlobalAddRecipeFragment()
|
||||||
R.id.recipes_list -> NavGraphDirections.actionGlobalRecipesFragment()
|
R.id.recipes_list -> actionGlobalRecipesListFragment()
|
||||||
R.id.change_url -> NavGraphDirections.actionGlobalBaseURLFragment()
|
R.id.change_url -> actionGlobalBaseURLFragment()
|
||||||
else -> throw IllegalArgumentException("Unknown menu item id: ${menuItem.itemId}")
|
else -> throw IllegalArgumentException("Unknown menu item id: ${menuItem.itemId}")
|
||||||
}
|
}
|
||||||
navigateTo(directions)
|
navigateTo(directions)
|
||||||
@@ -142,7 +145,7 @@ class MainActivity : AppCompatActivity(R.layout.main_activity) {
|
|||||||
logger.v { "onOptionsItemSelected() called with: item = $item" }
|
logger.v { "onOptionsItemSelected() called with: item = $item" }
|
||||||
val result = when (item.itemId) {
|
val result = when (item.itemId) {
|
||||||
R.id.login -> {
|
R.id.login -> {
|
||||||
navigateTo(NavGraphDirections.actionGlobalAuthenticationFragment())
|
navigateTo(actionGlobalAuthenticationFragment())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.logout -> {
|
R.id.logout -> {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class MainActivityViewModel @Inject constructor(
|
|||||||
_startDestination.value = when {
|
_startDestination.value = when {
|
||||||
!disclaimerStorage.isDisclaimerAccepted() -> R.id.disclaimerFragment
|
!disclaimerStorage.isDisclaimerAccepted() -> R.id.disclaimerFragment
|
||||||
serverInfoRepo.getUrl() == null -> R.id.baseURLFragment
|
serverInfoRepo.getUrl() == null -> R.id.baseURLFragment
|
||||||
else -> R.id.recipesFragment
|
else -> R.id.recipesListFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import gq.kirmanak.mealient.extensions.checkIfInputIsEmpty
|
|||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
import gq.kirmanak.mealient.ui.OperationUiState
|
import gq.kirmanak.mealient.ui.OperationUiState
|
||||||
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
||||||
|
import gq.kirmanak.mealient.ui.baseurl.BaseURLFragmentDirections.Companion.actionBaseURLFragmentToRecipesListFragment
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
@@ -56,7 +57,7 @@ class BaseURLFragment : Fragment(R.layout.fragment_base_url) {
|
|||||||
private fun onUiStateChange(uiState: OperationUiState<Unit>) = with(binding) {
|
private fun onUiStateChange(uiState: OperationUiState<Unit>) = with(binding) {
|
||||||
logger.v { "onUiStateChange() called with: uiState = $uiState" }
|
logger.v { "onUiStateChange() called with: uiState = $uiState" }
|
||||||
if (uiState.isSuccess) {
|
if (uiState.isSuccess) {
|
||||||
findNavController().navigate(BaseURLFragmentDirections.actionBaseURLFragmentToRecipesFragment())
|
findNavController().navigate(actionBaseURLFragmentToRecipesListFragment())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
urlInputLayout.error = when (val exception = uiState.exceptionOrNull) {
|
urlInputLayout.error = when (val exception = uiState.exceptionOrNull) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import gq.kirmanak.mealient.R
|
|||||||
import gq.kirmanak.mealient.databinding.FragmentDisclaimerBinding
|
import gq.kirmanak.mealient.databinding.FragmentDisclaimerBinding
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
||||||
|
import gq.kirmanak.mealient.ui.disclaimer.DisclaimerFragmentDirections.Companion.actionDisclaimerFragmentToBaseURLFragment
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
@@ -37,7 +38,7 @@ class DisclaimerFragment : Fragment(R.layout.fragment_disclaimer) {
|
|||||||
|
|
||||||
private fun navigateNext() {
|
private fun navigateNext() {
|
||||||
logger.v { "navigateNext() called" }
|
logger.v { "navigateNext() called" }
|
||||||
findNavController().navigate(DisclaimerFragmentDirections.actionDisclaimerFragmentToBaseURLFragment())
|
findNavController().navigate(actionDisclaimerFragmentToBaseURLFragment())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import by.kirich1409.viewbindingdelegate.viewBinding
|
|||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import gq.kirmanak.mealient.R
|
import gq.kirmanak.mealient.R
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
import gq.kirmanak.mealient.databinding.FragmentRecipesBinding
|
import gq.kirmanak.mealient.databinding.FragmentRecipesListBinding
|
||||||
import gq.kirmanak.mealient.datasource.NetworkError
|
import gq.kirmanak.mealient.datasource.NetworkError
|
||||||
import gq.kirmanak.mealient.extensions.collectWhenViewResumed
|
import gq.kirmanak.mealient.extensions.collectWhenViewResumed
|
||||||
import gq.kirmanak.mealient.extensions.refreshRequestFlow
|
import gq.kirmanak.mealient.extensions.refreshRequestFlow
|
||||||
@@ -23,6 +23,7 @@ import gq.kirmanak.mealient.extensions.showLongToast
|
|||||||
import gq.kirmanak.mealient.extensions.valueUpdatesOnly
|
import gq.kirmanak.mealient.extensions.valueUpdatesOnly
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
||||||
|
import gq.kirmanak.mealient.ui.recipes.RecipesListFragmentDirections.Companion.actionRecipesFragmentToRecipeInfoFragment
|
||||||
import gq.kirmanak.mealient.ui.recipes.images.RecipePreloaderFactory
|
import gq.kirmanak.mealient.ui.recipes.images.RecipePreloaderFactory
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
@@ -31,10 +32,10 @@ import kotlinx.coroutines.flow.map
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class RecipesFragment : Fragment(R.layout.fragment_recipes) {
|
class RecipesListFragment : Fragment(R.layout.fragment_recipes_list) {
|
||||||
|
|
||||||
private val binding by viewBinding(FragmentRecipesBinding::bind)
|
private val binding by viewBinding(FragmentRecipesListBinding::bind)
|
||||||
private val viewModel by viewModels<RecipeViewModel>()
|
private val viewModel by viewModels<RecipesListViewModel>()
|
||||||
private val activityViewModel by activityViewModels<MainActivityViewModel>()
|
private val activityViewModel by activityViewModels<MainActivityViewModel>()
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -62,7 +63,7 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) {
|
|||||||
|
|
||||||
private fun navigateToRecipeInfo(id: String) {
|
private fun navigateToRecipeInfo(id: String) {
|
||||||
logger.v { "navigateToRecipeInfo() called with: id = $id" }
|
logger.v { "navigateToRecipeInfo() called with: id = $id" }
|
||||||
val directions = RecipesFragmentDirections.actionRecipesFragmentToRecipeInfoFragment(id)
|
val directions = actionRecipesFragmentToRecipeInfoFragment(id)
|
||||||
findNavController().navigate(directions)
|
findNavController().navigate(directions)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +110,11 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) {
|
|||||||
showLongToast(R.string.fragment_recipes_last_page_loaded_toast)
|
showLongToast(R.string.fragment_recipes_last_page_loaded_toast)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
collectWhenViewResumed(recipesAdapter.sourceIsRefreshing()) { disableSwipeRefresh ->
|
||||||
|
logger.v { "setupRecipeAdapter: changing refresher enabled state to ${!disableSwipeRefresh}" }
|
||||||
|
binding.refresher.isEnabled = !disableSwipeRefresh
|
||||||
|
}
|
||||||
|
|
||||||
collectWhenViewResumed(recipesAdapter.refreshErrors()) {
|
collectWhenViewResumed(recipesAdapter.refreshErrors()) {
|
||||||
onLoadFailure(it)
|
onLoadFailure(it)
|
||||||
}
|
}
|
||||||
@@ -117,15 +123,6 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) {
|
|||||||
logger.v { "setupRecipeAdapter: received refresh request" }
|
logger.v { "setupRecipeAdapter: received refresh request" }
|
||||||
recipesAdapter.refresh()
|
recipesAdapter.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.isAuthorized.observe(viewLifecycleOwner) { isAuthorized ->
|
|
||||||
logger.v { "setupRecipeAdapter: isAuthorized changed to $isAuthorized" }
|
|
||||||
if (isAuthorized != null) {
|
|
||||||
if (isAuthorized) recipesAdapter.refresh()
|
|
||||||
// else is ignored to avoid the removal of the non-public recipes
|
|
||||||
viewModel.onAuthorizationChangeHandled()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onLoadFailure(error: Throwable) {
|
private fun onLoadFailure(error: Throwable) {
|
||||||
@@ -156,11 +153,21 @@ private fun Throwable.toLoadErrorReasonText(): Int? = when (this) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun <T : Any, VH : RecyclerView.ViewHolder> PagingDataAdapter<T, VH>.refreshErrors(): Flow<Throwable> {
|
private fun <T : Any, VH : RecyclerView.ViewHolder> PagingDataAdapter<T, VH>.refreshErrors(): Flow<Throwable> {
|
||||||
return loadStateFlow.map { it.refresh }.valueUpdatesOnly().filterIsInstance<LoadState.Error>()
|
return loadStateFlow
|
||||||
|
.map { it.refresh }
|
||||||
|
.valueUpdatesOnly()
|
||||||
|
.filterIsInstance<LoadState.Error>()
|
||||||
.map { it.error }
|
.map { it.error }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T : Any, VH : RecyclerView.ViewHolder> PagingDataAdapter<T, VH>.appendPaginationEnd(): Flow<Unit> {
|
private fun <T : Any, VH : RecyclerView.ViewHolder> PagingDataAdapter<T, VH>.appendPaginationEnd(): Flow<Unit> {
|
||||||
return loadStateFlow.map { it.append.endOfPaginationReached }.valueUpdatesOnly().filter { it }
|
return loadStateFlow
|
||||||
|
.map { it.append.endOfPaginationReached }
|
||||||
|
.valueUpdatesOnly()
|
||||||
|
.filter { it }
|
||||||
.map { }
|
.map { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun <T : Any, VH : RecyclerView.ViewHolder> PagingDataAdapter<T, VH>.sourceIsRefreshing(): Flow<Boolean> {
|
||||||
|
return loadStateFlow.map { it.source.refresh !is LoadState.NotLoading }.valueUpdatesOnly()
|
||||||
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package gq.kirmanak.mealient.ui.recipes
|
package gq.kirmanak.mealient.ui.recipes
|
||||||
|
|
||||||
import androidx.lifecycle.*
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.liveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.paging.cachedIn
|
import androidx.paging.cachedIn
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import gq.kirmanak.mealient.data.auth.AuthRepo
|
import gq.kirmanak.mealient.data.auth.AuthRepo
|
||||||
@@ -12,7 +15,7 @@ import kotlinx.coroutines.flow.onEach
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class RecipeViewModel @Inject constructor(
|
class RecipesListViewModel @Inject constructor(
|
||||||
private val recipeRepo: RecipeRepo,
|
private val recipeRepo: RecipeRepo,
|
||||||
authRepo: AuthRepo,
|
authRepo: AuthRepo,
|
||||||
private val logger: Logger,
|
private val logger: Logger,
|
||||||
@@ -20,21 +23,13 @@ class RecipeViewModel @Inject constructor(
|
|||||||
|
|
||||||
val pagingData = recipeRepo.createPager().flow.cachedIn(viewModelScope)
|
val pagingData = recipeRepo.createPager().flow.cachedIn(viewModelScope)
|
||||||
|
|
||||||
private val _isAuthorized = MutableLiveData<Boolean?>(null)
|
|
||||||
val isAuthorized: LiveData<Boolean?> = _isAuthorized
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
authRepo.isAuthorizedFlow.valueUpdatesOnly().onEach {
|
authRepo.isAuthorizedFlow.valueUpdatesOnly().onEach { hasAuthorized ->
|
||||||
logger.v { "Authorization state changed to $it" }
|
logger.v { "Authorization state changed to $hasAuthorized" }
|
||||||
_isAuthorized.postValue(it)
|
if (hasAuthorized) recipeRepo.refreshRecipes()
|
||||||
}.launchIn(viewModelScope)
|
}.launchIn(viewModelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onAuthorizationChangeHandled() {
|
|
||||||
logger.v { "onAuthorizationSuccessHandled() called" }
|
|
||||||
_isAuthorized.postValue(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun refreshRecipeInfo(recipeSlug: String): LiveData<Result<Unit>> {
|
fun refreshRecipeInfo(recipeSlug: String): LiveData<Result<Unit>> {
|
||||||
logger.v { "refreshRecipeInfo called with: recipeSlug = $recipeSlug" }
|
logger.v { "refreshRecipeInfo called with: recipeSlug = $recipeSlug" }
|
||||||
return liveData {
|
return liveData {
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".ui.recipes.RecipesFragment">
|
tools:context=".ui.recipes.RecipesListFragment">
|
||||||
|
|
||||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
android:id="@+id/refresher"
|
android:id="@+id/refresher"
|
||||||
@@ -12,10 +12,10 @@
|
|||||||
tools:layout="@layout/fragment_authentication" />
|
tools:layout="@layout/fragment_authentication" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/recipesFragment"
|
android:id="@+id/recipesListFragment"
|
||||||
android:name="gq.kirmanak.mealient.ui.recipes.RecipesFragment"
|
android:name="gq.kirmanak.mealient.ui.recipes.RecipesListFragment"
|
||||||
android:label="fragment_recipes"
|
android:label="fragment_recipes"
|
||||||
tools:layout="@layout/fragment_recipes">
|
tools:layout="@layout/fragment_recipes_list">
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_recipesFragment_to_recipeInfoFragment"
|
android:id="@+id/action_recipesFragment_to_recipeInfoFragment"
|
||||||
app:destination="@id/recipeInfoFragment" />
|
app:destination="@id/recipeInfoFragment" />
|
||||||
@@ -49,8 +49,8 @@
|
|||||||
android:label="fragment_base_url"
|
android:label="fragment_base_url"
|
||||||
tools:layout="@layout/fragment_base_url">
|
tools:layout="@layout/fragment_base_url">
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_baseURLFragment_to_recipesFragment"
|
android:id="@+id/action_baseURLFragment_to_recipesListFragment"
|
||||||
app:destination="@id/recipesFragment"
|
app:destination="@id/recipesListFragment"
|
||||||
app:popUpTo="@id/nav_graph"
|
app:popUpTo="@id/nav_graph"
|
||||||
app:popUpToInclusive="true" />
|
app:popUpToInclusive="true" />
|
||||||
</fragment>
|
</fragment>
|
||||||
@@ -66,8 +66,8 @@
|
|||||||
app:destination="@id/authenticationFragment" />
|
app:destination="@id/authenticationFragment" />
|
||||||
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_global_recipesFragment"
|
android:id="@+id/action_global_recipesListFragment"
|
||||||
app:destination="@id/recipesFragment" />
|
app:destination="@id/recipesListFragment" />
|
||||||
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_global_addRecipeFragment"
|
android:id="@+id/action_global_addRecipeFragment"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import kotlinx.coroutines.test.runTest
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class RecipeViewModelTest : BaseUnitTest() {
|
class RecipesListViewModelTest : BaseUnitTest() {
|
||||||
|
|
||||||
@MockK
|
@MockK
|
||||||
lateinit var authRepo: AuthRepo
|
lateinit var authRepo: AuthRepo
|
||||||
@@ -25,29 +25,24 @@ class RecipeViewModelTest : BaseUnitTest() {
|
|||||||
lateinit var recipeRepo: RecipeRepo
|
lateinit var recipeRepo: RecipeRepo
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when authRepo isAuthorized changes to true expect isAuthorized update`() {
|
fun `when authRepo isAuthorized changes to true expect that recipes are refreshed`() {
|
||||||
every { authRepo.isAuthorizedFlow } returns flowOf(false, true)
|
every { authRepo.isAuthorizedFlow } returns flowOf(false, true)
|
||||||
assertThat(createSubject().isAuthorized.value).isTrue()
|
createSubject()
|
||||||
|
coVerify { recipeRepo.refreshRecipes() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when authRepo isAuthorized changes to false expect isAuthorized update`() {
|
fun `when authRepo isAuthorized changes to false expect that recipes are not refreshed`() {
|
||||||
every { authRepo.isAuthorizedFlow } returns flowOf(true, false)
|
every { authRepo.isAuthorizedFlow } returns flowOf(true, false)
|
||||||
assertThat(createSubject().isAuthorized.value).isFalse()
|
createSubject()
|
||||||
|
coVerify(inverse = true) { recipeRepo.refreshRecipes() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when authRepo isAuthorized doesn't change expect isAuthorized null`() {
|
fun `when authRepo isAuthorized doesn't change expect that recipes are not refreshed`() {
|
||||||
every { authRepo.isAuthorizedFlow } returns flowOf(true)
|
every { authRepo.isAuthorizedFlow } returns flowOf(true)
|
||||||
assertThat(createSubject().isAuthorized.value).isNull()
|
createSubject()
|
||||||
}
|
coVerify(inverse = true) { recipeRepo.refreshRecipes() }
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when isAuthorization change is handled expect isAuthorized null`() {
|
|
||||||
every { authRepo.isAuthorizedFlow } returns flowOf(true, false)
|
|
||||||
val subject = createSubject()
|
|
||||||
subject.onAuthorizationChangeHandled()
|
|
||||||
assertThat(subject.isAuthorized.value).isNull()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -78,5 +73,5 @@ class RecipeViewModelTest : BaseUnitTest() {
|
|||||||
assertThat(actual).isEqualTo(result)
|
assertThat(actual).isEqualTo(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createSubject() = RecipeViewModel(recipeRepo, authRepo, logger)
|
private fun createSubject() = RecipesListViewModel(recipeRepo, authRepo, logger)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user