diff --git a/app/src/main/java/gq/kirmanak/mealient/ui/activity/MainActivity.kt b/app/src/main/java/gq/kirmanak/mealient/ui/activity/MainActivity.kt index 478002d..08aac96 100644 --- a/app/src/main/java/gq/kirmanak/mealient/ui/activity/MainActivity.kt +++ b/app/src/main/java/gq/kirmanak/mealient/ui/activity/MainActivity.kt @@ -12,16 +12,14 @@ import com.google.android.material.shape.MaterialShapeDrawable import dagger.hilt.android.AndroidEntryPoint import gq.kirmanak.mealient.R import gq.kirmanak.mealient.databinding.MainActivityBinding -import gq.kirmanak.mealient.ui.auth.AuthenticationState -import gq.kirmanak.mealient.ui.auth.AuthenticationState.AUTHORIZED -import gq.kirmanak.mealient.ui.auth.AuthenticationState.UNAUTHORIZED import timber.log.Timber @AndroidEntryPoint class MainActivity : AppCompatActivity() { private lateinit var binding: MainActivityBinding private val viewModel by viewModels() - private var lastAuthenticationState: AuthenticationState? = null + private val title: String by lazy { getString(R.string.app_name) } + private val uiState: MainActivityUiState get() = viewModel.uiState override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -31,7 +29,13 @@ class MainActivity : AppCompatActivity() { setSupportActionBar(binding.toolbar) supportActionBar?.setIcon(R.drawable.ic_toolbar) setToolbarRoundCorner() - listenToAuthStatuses() + viewModel.uiStateLive.observe(this, ::onUiStateChange) + } + + private fun onUiStateChange(uiState: MainActivityUiState) { + Timber.v("onUiStateChange() called with: uiState = $uiState") + supportActionBar?.title = if (uiState.titleVisible) title else null + invalidateOptionsMenu() } private fun setToolbarRoundCorner() { @@ -51,22 +55,11 @@ class MainActivity : AppCompatActivity() { } } - private fun listenToAuthStatuses() { - Timber.v("listenToAuthStatuses() called") - viewModel.authenticationStateLive.observe(this, ::onAuthStateUpdate) - } - - private fun onAuthStateUpdate(authState: AuthenticationState) { - Timber.v("onAuthStateUpdate() called with: it = $authState") - lastAuthenticationState = authState - invalidateOptionsMenu() - } - override fun onCreateOptionsMenu(menu: Menu): Boolean { Timber.v("onCreateOptionsMenu() called with: menu = $menu") menuInflater.inflate(R.menu.main_toolbar, menu) - menu.findItem(R.id.logout).isVisible = lastAuthenticationState == AUTHORIZED - menu.findItem(R.id.login).isVisible = lastAuthenticationState == UNAUTHORIZED + menu.findItem(R.id.logout).isVisible = uiState.canShowLogout + menu.findItem(R.id.login).isVisible = uiState.canShowLogin return true } diff --git a/app/src/main/java/gq/kirmanak/mealient/ui/activity/MainActivityUiState.kt b/app/src/main/java/gq/kirmanak/mealient/ui/activity/MainActivityUiState.kt new file mode 100644 index 0000000..c9b5e82 --- /dev/null +++ b/app/src/main/java/gq/kirmanak/mealient/ui/activity/MainActivityUiState.kt @@ -0,0 +1,13 @@ +package gq.kirmanak.mealient.ui.activity + +data class MainActivityUiState( + val loginButtonVisible: Boolean = false, + val titleVisible: Boolean = true, + val isAuthorized: Boolean = false, +) { + val canShowLogin: Boolean + get() = !isAuthorized && loginButtonVisible + + val canShowLogout: Boolean + get() = isAuthorized && loginButtonVisible +} diff --git a/app/src/main/java/gq/kirmanak/mealient/ui/activity/MainActivityViewModel.kt b/app/src/main/java/gq/kirmanak/mealient/ui/activity/MainActivityViewModel.kt index 6815084..7290723 100644 --- a/app/src/main/java/gq/kirmanak/mealient/ui/activity/MainActivityViewModel.kt +++ b/app/src/main/java/gq/kirmanak/mealient/ui/activity/MainActivityViewModel.kt @@ -1,14 +1,10 @@ package gq.kirmanak.mealient.ui.activity -import androidx.lifecycle.LiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.asLiveData -import androidx.lifecycle.viewModelScope +import androidx.lifecycle.* import dagger.hilt.android.lifecycle.HiltViewModel import gq.kirmanak.mealient.data.auth.AuthRepo -import gq.kirmanak.mealient.ui.auth.AuthenticationState -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject @@ -18,16 +14,22 @@ class MainActivityViewModel @Inject constructor( private val authRepo: AuthRepo, ) : ViewModel() { - private val showLoginButtonFlow = MutableStateFlow(false) - var showLoginButton: Boolean by showLoginButtonFlow::value + private val _uiState = MutableLiveData(MainActivityUiState()) + val uiStateLive: LiveData + get() = _uiState.distinctUntilChanged() + var uiState: MainActivityUiState + get() = checkNotNull(_uiState.value) { "UiState must not be null" } + private set(value) = _uiState.postValue(value) - private val authenticationStateFlow = combine( - showLoginButtonFlow, - authRepo.isAuthorizedFlow, - AuthenticationState::determineState - ) - val authenticationStateLive: LiveData - get() = authenticationStateFlow.asLiveData() + init { + authRepo.isAuthorizedFlow + .onEach { isAuthorized -> updateUiState { it.copy(isAuthorized = isAuthorized) } } + .launchIn(viewModelScope) + } + + fun updateUiState(updater: (MainActivityUiState) -> MainActivityUiState) { + uiState = updater(uiState) + } fun logout() { Timber.v("logout() called") diff --git a/app/src/main/java/gq/kirmanak/mealient/ui/auth/AuthenticationFragment.kt b/app/src/main/java/gq/kirmanak/mealient/ui/auth/AuthenticationFragment.kt index 1aa024c..e0d5743 100644 --- a/app/src/main/java/gq/kirmanak/mealient/ui/auth/AuthenticationFragment.kt +++ b/app/src/main/java/gq/kirmanak/mealient/ui/auth/AuthenticationFragment.kt @@ -2,8 +2,8 @@ package gq.kirmanak.mealient.ui.auth import android.os.Bundle import android.view.View -import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import by.kirich1409.viewbindingdelegate.viewBinding @@ -12,19 +12,20 @@ import gq.kirmanak.mealient.R import gq.kirmanak.mealient.data.network.NetworkError import gq.kirmanak.mealient.databinding.FragmentAuthenticationBinding import gq.kirmanak.mealient.extensions.checkIfInputIsEmpty +import gq.kirmanak.mealient.ui.activity.MainActivityViewModel import timber.log.Timber @AndroidEntryPoint class AuthenticationFragment : Fragment(R.layout.fragment_authentication) { private val binding by viewBinding(FragmentAuthenticationBinding::bind) private val viewModel by viewModels() + private val activityViewModel by activityViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) Timber.v("onViewCreated() called with: view = $view, savedInstanceState = $savedInstanceState") binding.button.setOnClickListener { onLoginClicked() } - (requireActivity() as? AppCompatActivity)?.supportActionBar?.title = - getString(R.string.app_name) + activityViewModel.updateUiState { it.copy(loginButtonVisible = false, titleVisible = true) } viewModel.authenticationResult.observe(viewLifecycleOwner, ::onAuthenticationResult) } diff --git a/app/src/main/java/gq/kirmanak/mealient/ui/baseurl/BaseURLFragment.kt b/app/src/main/java/gq/kirmanak/mealient/ui/baseurl/BaseURLFragment.kt index d30441e..a3f5513 100644 --- a/app/src/main/java/gq/kirmanak/mealient/ui/baseurl/BaseURLFragment.kt +++ b/app/src/main/java/gq/kirmanak/mealient/ui/baseurl/BaseURLFragment.kt @@ -3,6 +3,7 @@ package gq.kirmanak.mealient.ui.baseurl import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import by.kirich1409.viewbindingdelegate.viewBinding @@ -11,6 +12,7 @@ import gq.kirmanak.mealient.R import gq.kirmanak.mealient.data.network.NetworkError import gq.kirmanak.mealient.databinding.FragmentBaseUrlBinding import gq.kirmanak.mealient.extensions.checkIfInputIsEmpty +import gq.kirmanak.mealient.ui.activity.MainActivityViewModel import timber.log.Timber @AndroidEntryPoint @@ -18,12 +20,14 @@ class BaseURLFragment : Fragment(R.layout.fragment_base_url) { private val binding by viewBinding(FragmentBaseUrlBinding::bind) private val viewModel by viewModels() + private val activityViewModel by activityViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) Timber.v("onViewCreated() called with: view = $view, savedInstanceState = $savedInstanceState") binding.button.setOnClickListener(::onProceedClick) viewModel.checkURLResult.observe(viewLifecycleOwner, ::onCheckURLResult) + activityViewModel.updateUiState { it.copy(loginButtonVisible = false, titleVisible = true) } } private fun onProceedClick(view: View) { diff --git a/app/src/main/java/gq/kirmanak/mealient/ui/disclaimer/DisclaimerFragment.kt b/app/src/main/java/gq/kirmanak/mealient/ui/disclaimer/DisclaimerFragment.kt index b9ac72e..f306505 100644 --- a/app/src/main/java/gq/kirmanak/mealient/ui/disclaimer/DisclaimerFragment.kt +++ b/app/src/main/java/gq/kirmanak/mealient/ui/disclaimer/DisclaimerFragment.kt @@ -2,20 +2,22 @@ package gq.kirmanak.mealient.ui.disclaimer import android.os.Bundle import android.view.View -import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import by.kirich1409.viewbindingdelegate.viewBinding import dagger.hilt.android.AndroidEntryPoint import gq.kirmanak.mealient.R import gq.kirmanak.mealient.databinding.FragmentDisclaimerBinding +import gq.kirmanak.mealient.ui.activity.MainActivityViewModel import timber.log.Timber @AndroidEntryPoint class DisclaimerFragment : Fragment(R.layout.fragment_disclaimer) { private val binding by viewBinding(FragmentDisclaimerBinding::bind) private val viewModel by viewModels() + private val activityViewModel by activityViewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -48,7 +50,6 @@ class DisclaimerFragment : Fragment(R.layout.fragment_disclaimer) { binding.okay.isClickable = it == 0 } viewModel.startCountDown() - (requireActivity() as? AppCompatActivity)?.supportActionBar?.title = - getString(R.string.app_name) + activityViewModel.updateUiState { it.copy(loginButtonVisible = false, titleVisible = true) } } } \ No newline at end of file diff --git a/app/src/main/java/gq/kirmanak/mealient/ui/recipes/RecipesFragment.kt b/app/src/main/java/gq/kirmanak/mealient/ui/recipes/RecipesFragment.kt index 14ba126..a961ea4 100644 --- a/app/src/main/java/gq/kirmanak/mealient/ui/recipes/RecipesFragment.kt +++ b/app/src/main/java/gq/kirmanak/mealient/ui/recipes/RecipesFragment.kt @@ -2,7 +2,6 @@ package gq.kirmanak.mealient.ui.recipes import android.os.Bundle import android.view.View -import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels @@ -26,9 +25,8 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) Timber.v("onViewCreated() called with: view = $view, savedInstanceState = $savedInstanceState") - activityViewModel.showLoginButton = true + activityViewModel.updateUiState { it.copy(loginButtonVisible = true, titleVisible = false) } setupRecipeAdapter() - (requireActivity() as? AppCompatActivity)?.supportActionBar?.title = null } private fun navigateToRecipeInfo(recipeSummaryEntity: RecipeSummaryEntity) { @@ -64,6 +62,5 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) { Timber.v("onDestroyView() called") // Prevent RV leaking through mObservers list in adapter binding.recipes.adapter = null - activityViewModel.showLoginButton = false } } \ No newline at end of file diff --git a/app/src/main/res/menu/main_toolbar.xml b/app/src/main/res/menu/main_toolbar.xml index bad8b2b..6d9ba04 100644 --- a/app/src/main/res/menu/main_toolbar.xml +++ b/app/src/main/res/menu/main_toolbar.xml @@ -6,7 +6,7 @@ android:id="@+id/login" android:contentDescription="@string/menu_main_toolbar_content_description_login" android:title="@string/menu_main_toolbar_login" - app:showAsAction="never" /> + app:showAsAction="ifRoom" />