Merge pull request #32 from kirmanak/fixes

Fix several issues
This commit is contained in:
Kirill Kamakin
2022-04-04 21:00:15 +05:00
committed by GitHub
11 changed files with 130 additions and 140 deletions

View File

@@ -19,8 +19,7 @@ import timber.log.Timber
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private lateinit var binding: MainActivityBinding private lateinit var binding: MainActivityBinding
private val authViewModel by viewModels<AuthenticationViewModel>() private val authViewModel by viewModels<AuthenticationViewModel>()
private val authenticationState: AuthenticationState private var lastAuthenticationState: AuthenticationState? = null
get() = authViewModel.currentAuthenticationState
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -52,31 +51,29 @@ class MainActivity : AppCompatActivity() {
private fun listenToAuthStatuses() { private fun listenToAuthStatuses() {
Timber.v("listenToAuthStatuses() called") Timber.v("listenToAuthStatuses() called")
authViewModel.authenticationState.observe(this, ::onAuthStateUpdate) authViewModel.authenticationStateLive.observe(this, ::onAuthStateUpdate)
} }
private fun onAuthStateUpdate(authState: AuthenticationState) { private fun onAuthStateUpdate(authState: AuthenticationState) {
Timber.v("onAuthStateUpdate() called with: it = $authState") Timber.v("onAuthStateUpdate() called with: it = $authState")
lastAuthenticationState = authState
invalidateOptionsMenu() invalidateOptionsMenu()
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
Timber.v("onCreateOptionsMenu() called with: menu = $menu") Timber.v("onCreateOptionsMenu() called with: menu = $menu")
menuInflater.inflate(R.menu.main_toolbar, menu) menuInflater.inflate(R.menu.main_toolbar, menu)
menu.findItem(R.id.logout).isVisible = authenticationState == AUTHORIZED menu.findItem(R.id.logout).isVisible = lastAuthenticationState == AUTHORIZED
menu.findItem(R.id.login).isVisible = authenticationState == UNAUTHORIZED menu.findItem(R.id.login).isVisible = lastAuthenticationState == UNAUTHORIZED
return true return true
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
Timber.v("onOptionsItemSelected() called with: item = $item") Timber.v("onOptionsItemSelected() called with: item = $item")
val result = when (item.itemId) { val result = when (item.itemId) {
R.id.logout -> { R.id.logout, R.id.login -> {
authViewModel.logout() // When user clicks logout they don't want to be authorized
true authViewModel.authRequested = item.itemId == R.id.login
}
R.id.login -> {
authViewModel.login()
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)

View File

@@ -0,0 +1,36 @@
package gq.kirmanak.mealient.extensions
import androidx.activity.OnBackPressedDispatcher
import androidx.activity.addCallback
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
fun Fragment.executeOnceOnBackPressed(action: () -> Unit) {
val onBackPressedDispatcher = requireActivity().onBackPressedDispatcher
lifecycleScope.launch {
onBackPressedDispatcher.backPressedFlow().first()
action()
onBackPressedDispatcher.onBackPressed() // Execute other callbacks now
}
}
@OptIn(ExperimentalCoroutinesApi::class)
fun OnBackPressedDispatcher.backPressedFlow(): Flow<Unit> = callbackFlow {
val callback = addCallback { trySend(Unit) }
awaitClose {
callback.isEnabled = false
callback.remove()
}
}
inline fun <T> Fragment.collectWithViewLifecycle(
flow: Flow<T>,
crossinline collector: suspend (T) -> Unit,
) = viewLifecycleOwner.lifecycleScope.launch { flow.collect(collector) }

View File

@@ -1,4 +1,4 @@
package gq.kirmanak.mealient.ui package gq.kirmanak.mealient.extensions
import android.app.Activity import android.app.Activity
import android.os.Build import android.os.Build
@@ -10,8 +10,6 @@ import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.widget.doAfterTextChanged import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.LifecycleCoroutineScope import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -26,20 +24,17 @@ import kotlinx.coroutines.flow.first
import timber.log.Timber import timber.log.Timber
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
fun SwipeRefreshLayout.refreshesLiveData(): LiveData<Unit> { fun SwipeRefreshLayout.refreshRequestFlow(): Flow<Unit> = callbackFlow {
val callbackFlow: Flow<Unit> = callbackFlow { Timber.v("refreshRequestFlow() called")
val listener = SwipeRefreshLayout.OnRefreshListener { val listener = SwipeRefreshLayout.OnRefreshListener {
Timber.v("Refresh requested") Timber.v("refreshRequestFlow: listener called")
trySend(Unit).logErrors("refreshesFlow") trySend(Unit).logErrors("refreshesFlow")
} }
Timber.v("Adding refresh request listener")
setOnRefreshListener(listener) setOnRefreshListener(listener)
awaitClose { awaitClose {
Timber.v("Removing refresh request listener") Timber.v("Removing refresh request listener")
setOnRefreshListener(null) setOnRefreshListener(null)
} }
}
return callbackFlow.asLiveData()
} }
fun Activity.setSystemUiVisibility(isVisible: Boolean) { fun Activity.setSystemUiVisibility(isVisible: Boolean) {

View File

@@ -5,15 +5,16 @@ import android.view.View
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.LiveData
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import by.kirich1409.viewbindingdelegate.viewBinding 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.data.network.NetworkError.Unauthorized import gq.kirmanak.mealient.data.network.NetworkError
import gq.kirmanak.mealient.databinding.FragmentAuthenticationBinding import gq.kirmanak.mealient.databinding.FragmentAuthenticationBinding
import gq.kirmanak.mealient.ui.checkIfInputIsEmpty import gq.kirmanak.mealient.extensions.checkIfInputIsEmpty
import gq.kirmanak.mealient.extensions.executeOnceOnBackPressed
import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
@AndroidEntryPoint @AndroidEntryPoint
@@ -21,13 +22,10 @@ class AuthenticationFragment : Fragment(R.layout.fragment_authentication) {
private val binding by viewBinding(FragmentAuthenticationBinding::bind) private val binding by viewBinding(FragmentAuthenticationBinding::bind)
private val viewModel by activityViewModels<AuthenticationViewModel>() private val viewModel by activityViewModels<AuthenticationViewModel>()
private val authStatuses: LiveData<AuthenticationState>
get() = viewModel.authenticationState
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Timber.v("onCreate() called with: savedInstanceState = $savedInstanceState") Timber.v("onCreate() called with: savedInstanceState = $savedInstanceState")
authStatuses.observe(this, ::onAuthStatusChange) executeOnceOnBackPressed { viewModel.authRequested = false }
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -38,13 +36,6 @@ class AuthenticationFragment : Fragment(R.layout.fragment_authentication) {
getString(R.string.app_name) getString(R.string.app_name)
} }
private fun onAuthStatusChange(isAuthenticated: AuthenticationState) {
Timber.v("onAuthStatusChange() called with: isAuthenticated = $isAuthenticated")
if (isAuthenticated == AuthenticationState.AUTHORIZED) {
findNavController().popBackStack()
}
}
private fun onLoginClicked(): Unit = with(binding) { private fun onLoginClicked(): Unit = with(binding) {
Timber.v("onLoginClicked() called") Timber.v("onLoginClicked() called")
@@ -57,14 +48,23 @@ class AuthenticationFragment : Fragment(R.layout.fragment_authentication) {
} ?: return } ?: return
button.isClickable = false button.isClickable = false
viewModel.authenticate(email, pass).observe(viewLifecycleOwner) { viewLifecycleOwner.lifecycleScope.launch {
Timber.d("onLoginClicked: result $it") onAuthenticationResult(viewModel.authenticate(email, pass))
passwordInputLayout.error = when (it.exceptionOrNull()) { }
is Unauthorized -> getString(R.string.fragment_authentication_credentials_incorrect) }
private fun onAuthenticationResult(result: Result<Unit>) {
Timber.v("onAuthenticationResult() called with: result = $result")
if (result.isSuccess) {
findNavController().popBackStack()
return
}
binding.passwordInputLayout.error = when (result.exceptionOrNull()) {
is NetworkError.Unauthorized -> getString(R.string.fragment_authentication_credentials_incorrect)
else -> null else -> null
} }
button.isClickable = true binding.button.isClickable = true
}
} }
} }

View File

@@ -5,16 +5,19 @@ import timber.log.Timber
enum class AuthenticationState { enum class AuthenticationState {
AUTHORIZED, AUTHORIZED,
AUTH_REQUESTED, AUTH_REQUESTED,
UNAUTHORIZED; UNAUTHORIZED,
UNKNOWN;
companion object { companion object {
fun determineState( fun determineState(
isLoginRequested: Boolean, isLoginRequested: Boolean,
showLoginButton: Boolean,
isAuthorized: Boolean, isAuthorized: Boolean,
): AuthenticationState { ): AuthenticationState {
Timber.v("determineState() called with: isLoginRequested = $isLoginRequested, isAuthorized = $isAuthorized") Timber.v("determineState() called with: isLoginRequested = $isLoginRequested, showLoginButton = $showLoginButton, isAuthorized = $isAuthorized")
val result = when { val result = when {
!showLoginButton -> UNKNOWN
isAuthorized -> AUTHORIZED isAuthorized -> AUTHORIZED
isLoginRequested -> AUTH_REQUESTED isLoginRequested -> AUTH_REQUESTED
else -> UNAUTHORIZED else -> UNAUTHORIZED

View File

@@ -1,9 +1,13 @@
package gq.kirmanak.mealient.ui.auth package gq.kirmanak.mealient.ui.auth
import androidx.lifecycle.* import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
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
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
@@ -14,41 +18,31 @@ class AuthenticationViewModel @Inject constructor(
private val authRepo: AuthRepo, private val authRepo: AuthRepo,
) : ViewModel() { ) : ViewModel() {
private val loginRequestsFlow = MutableStateFlow(false) private val authRequestsFlow = MutableStateFlow(false)
val authenticationState: LiveData<AuthenticationState> = loginRequestsFlow.combine( private val showLoginButtonFlow = MutableStateFlow(false)
flow = authRepo.isAuthorizedFlow, private val authenticationStateFlow = combine(
transform = AuthenticationState::determineState authRequestsFlow,
).asLiveData() showLoginButtonFlow,
val currentAuthenticationState: AuthenticationState authRepo.isAuthorizedFlow,
get() = checkNotNull(authenticationState.value) { "Auth state flow mustn't be null" } AuthenticationState::determineState
)
val authenticationStateLive: LiveData<AuthenticationState>
get() = authenticationStateFlow.asLiveData()
var authRequested: Boolean by authRequestsFlow::value
var showLoginButton: Boolean by showLoginButtonFlow::value
fun authenticate(username: String, password: String): LiveData<Result<Unit>> { init {
Timber.v("authenticate() called with: username = $username, password = $password")
val result = MutableLiveData<Result<Unit>>()
viewModelScope.launch { viewModelScope.launch {
runCatching { authRequestsFlow.collect { isRequested ->
// Clear auth token on logout request
if (!isRequested) authRepo.logout()
}
}
}
suspend fun authenticate(username: String, password: String): Result<Unit> = runCatching {
authRepo.authenticate(username, password) authRepo.authenticate(username, password)
}.onFailure { }.onFailure {
Timber.e(it, "authenticate: can't authenticate") Timber.e(it, "authenticate: can't authenticate")
result.value = Result.failure(it)
}.onSuccess {
Timber.d("authenticate: authenticated")
result.value = Result.success(Unit)
}
}
return result
}
fun logout() {
Timber.v("logout() called")
viewModelScope.launch {
loginRequestsFlow.emit(false)
authRepo.logout()
}
}
fun login() {
Timber.v("login() called")
viewModelScope.launch { loginRequestsFlow.emit(true) }
} }
} }

View File

@@ -11,7 +11,7 @@ import dagger.hilt.android.AndroidEntryPoint
import gq.kirmanak.mealient.R import gq.kirmanak.mealient.R
import gq.kirmanak.mealient.data.network.NetworkError import gq.kirmanak.mealient.data.network.NetworkError
import gq.kirmanak.mealient.databinding.FragmentBaseUrlBinding import gq.kirmanak.mealient.databinding.FragmentBaseUrlBinding
import gq.kirmanak.mealient.ui.checkIfInputIsEmpty import gq.kirmanak.mealient.extensions.checkIfInputIsEmpty
import timber.log.Timber import timber.log.Timber
@AndroidEntryPoint @AndroidEntryPoint

View File

@@ -9,7 +9,7 @@ import timber.log.Timber
class RecipeViewHolder( class RecipeViewHolder(
private val binding: ViewHolderRecipeBinding, private val binding: ViewHolderRecipeBinding,
private val recipeViewModel: RecipeViewModel, private val recipeViewModel: RecipeViewModel,
private val clickListener: (RecipeSummaryEntity) -> Unit private val clickListener: (RecipeSummaryEntity) -> Unit,
) : RecyclerView.ViewHolder(binding.root) { ) : RecyclerView.ViewHolder(binding.root) {
private val loadingPlaceholder by lazy { private val loadingPlaceholder by lazy {
binding.root.resources.getString(R.string.view_holder_recipe_text_placeholder) binding.root.resources.getString(R.string.view_holder_recipe_text_placeholder)

View File

@@ -1,8 +1,6 @@
package gq.kirmanak.mealient.ui.recipes package gq.kirmanak.mealient.ui.recipes
import android.widget.ImageView import android.widget.ImageView
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.paging.cachedIn import androidx.paging.cachedIn
@@ -10,34 +8,17 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import gq.kirmanak.mealient.data.recipes.RecipeImageLoader import gq.kirmanak.mealient.data.recipes.RecipeImageLoader
import gq.kirmanak.mealient.data.recipes.RecipeRepo import gq.kirmanak.mealient.data.recipes.RecipeRepo
import gq.kirmanak.mealient.data.recipes.db.entity.RecipeSummaryEntity import gq.kirmanak.mealient.data.recipes.db.entity.RecipeSummaryEntity
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class RecipeViewModel @Inject constructor( class RecipeViewModel @Inject constructor(
private val recipeRepo: RecipeRepo, recipeRepo: RecipeRepo,
private val recipeImageLoader: RecipeImageLoader private val recipeImageLoader: RecipeImageLoader
) : ViewModel() { ) : ViewModel() {
private var _isRefreshing = MutableLiveData<Boolean>()
val isRefreshing: LiveData<Boolean> get() = _isRefreshing
private val _nextRecipeInfoChannel = Channel<RecipeSummaryEntity>() val pagingData = recipeRepo.createPager().flow.cachedIn(viewModelScope)
val nextRecipeInfo: Flow<RecipeSummaryEntity> =
_nextRecipeInfoChannel.receiveAsFlow()
val adapter = RecipesPagingAdapter(this) {
Timber.d("onClick: recipe clicked $it")
viewModelScope.launch { _nextRecipeInfoChannel.send(it) }
}
init {
setupAdapter()
}
fun loadRecipeImage(view: ImageView, recipeSummary: RecipeSummaryEntity?) { fun loadRecipeImage(view: ImageView, recipeSummary: RecipeSummaryEntity?) {
Timber.v("loadRecipeImage() called with: view = $view, recipeSummary = $recipeSummary") Timber.v("loadRecipeImage() called with: view = $view, recipeSummary = $recipeSummary")
@@ -45,21 +26,4 @@ class RecipeViewModel @Inject constructor(
recipeImageLoader.loadRecipeImage(view, recipeSummary?.slug) recipeImageLoader.loadRecipeImage(view, recipeSummary?.slug)
} }
} }
private fun setupAdapter() {
with(viewModelScope) {
launch {
recipeRepo.createPager().flow.cachedIn(this).collect {
Timber.d("setupAdapter: received data update")
adapter.submitData(it)
}
}
launch {
adapter.onPagesUpdatedFlow.collect {
Timber.d("setupAdapter: pages have been updated")
_isRefreshing.value = false
}
}
}
}
} }

View File

@@ -6,17 +6,16 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import by.kirich1409.viewbindingdelegate.viewBinding 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.data.recipes.db.entity.RecipeSummaryEntity import gq.kirmanak.mealient.data.recipes.db.entity.RecipeSummaryEntity
import gq.kirmanak.mealient.databinding.FragmentRecipesBinding import gq.kirmanak.mealient.databinding.FragmentRecipesBinding
import gq.kirmanak.mealient.extensions.collectWithViewLifecycle
import gq.kirmanak.mealient.extensions.refreshRequestFlow
import gq.kirmanak.mealient.ui.auth.AuthenticationState import gq.kirmanak.mealient.ui.auth.AuthenticationState
import gq.kirmanak.mealient.ui.auth.AuthenticationViewModel import gq.kirmanak.mealient.ui.auth.AuthenticationViewModel
import gq.kirmanak.mealient.ui.refreshesLiveData
import kotlinx.coroutines.flow.collect
import timber.log.Timber import timber.log.Timber
@AndroidEntryPoint @AndroidEntryPoint
@@ -27,7 +26,8 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
authViewModel.authenticationState.observe(this, ::onAuthStateChange) Timber.v("onCreate() called with: savedInstanceState = $savedInstanceState")
authViewModel.authenticationStateLive.observe(this, ::onAuthStateChange)
} }
private fun onAuthStateChange(authenticationState: AuthenticationState) { private fun onAuthStateChange(authenticationState: AuthenticationState) {
@@ -40,6 +40,7 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
Timber.v("onViewCreated() called with: view = $view, savedInstanceState = $savedInstanceState") Timber.v("onViewCreated() called with: view = $view, savedInstanceState = $savedInstanceState")
authViewModel.showLoginButton = true
setupRecipeAdapter() setupRecipeAdapter()
(requireActivity() as? AppCompatActivity)?.supportActionBar?.title = null (requireActivity() as? AppCompatActivity)?.supportActionBar?.title = null
} }
@@ -56,20 +57,19 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) {
private fun setupRecipeAdapter() { private fun setupRecipeAdapter() {
Timber.v("setupRecipeAdapter() called") Timber.v("setupRecipeAdapter() called")
binding.recipes.adapter = viewModel.adapter val adapter = RecipesPagingAdapter(viewModel, ::navigateToRecipeInfo)
viewModel.isRefreshing.observe(viewLifecycleOwner) { binding.recipes.adapter = adapter
Timber.d("setupRecipeAdapter: isRefreshing = $it") collectWithViewLifecycle(viewModel.pagingData) {
binding.refresher.isRefreshing = it Timber.v("setupRecipeAdapter: received data update")
adapter.submitData(lifecycle, it)
} }
binding.refresher.refreshesLiveData().observe(viewLifecycleOwner) { collectWithViewLifecycle(adapter.onPagesUpdatedFlow) {
Timber.d("setupRecipeAdapter: received refresh request") Timber.v("setupRecipeAdapter: pages updated")
viewModel.adapter.refresh() binding.refresher.isRefreshing = false
}
viewLifecycleOwner.lifecycleScope.launchWhenResumed {
viewModel.nextRecipeInfo.collect {
Timber.d("setupRecipeAdapter: navigating to recipe $it")
navigateToRecipeInfo(it)
} }
collectWithViewLifecycle(binding.refresher.refreshRequestFlow()) {
Timber.v("setupRecipeAdapter: received refresh request")
adapter.refresh()
} }
} }
@@ -78,5 +78,6 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) {
Timber.v("onDestroyView() called") Timber.v("onDestroyView() called")
// Prevent RV leaking through mObservers list in adapter // Prevent RV leaking through mObservers list in adapter
binding.recipes.adapter = null binding.recipes.adapter = null
authViewModel.showLoginButton = false
} }
} }

View File

@@ -9,8 +9,8 @@ import androidx.navigation.NavDirections
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import gq.kirmanak.mealient.R import gq.kirmanak.mealient.R
import gq.kirmanak.mealient.ui.setActionBarVisibility import gq.kirmanak.mealient.extensions.setActionBarVisibility
import gq.kirmanak.mealient.ui.setSystemUiVisibility import gq.kirmanak.mealient.extensions.setSystemUiVisibility
import timber.log.Timber import timber.log.Timber
@AndroidEntryPoint @AndroidEntryPoint