AuthViewModel: Switch from livedata to stateflow

* Also make authdata init private

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2024-09-25 19:10:17 +01:00
parent 9e8dd03cee
commit 9468ea7533
3 changed files with 85 additions and 79 deletions

View File

@@ -33,6 +33,7 @@ sealed class ViewState {
} }
sealed class AuthState { sealed class AuthState {
data object Init: AuthState()
data object Available : AuthState() data object Available : AuthState()
data object Unavailable : AuthState() data object Unavailable : AuthState()
data object SignedIn : AuthState() data object SignedIn : AuthState()

View File

@@ -24,6 +24,7 @@ import android.net.UrlQuerySanitizer
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.aurora.extensions.hide import com.aurora.extensions.hide
import com.aurora.extensions.show import com.aurora.extensions.show
@@ -36,6 +37,8 @@ import com.aurora.store.util.Preferences.PREFERENCE_INTRO
import com.aurora.store.view.ui.commons.BaseFragment import com.aurora.store.view.ui.commons.BaseFragment
import com.aurora.store.viewmodel.auth.AuthViewModel import com.aurora.store.viewmodel.auth.AuthViewModel
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
@AndroidEntryPoint @AndroidEntryPoint
class SplashFragment : BaseFragment<FragmentSplashBinding>() { class SplashFragment : BaseFragment<FragmentSplashBinding>() {
@@ -83,72 +86,70 @@ class SplashFragment : BaseFragment<FragmentSplashBinding>() {
binding.btnAnonymous.visibility = View.VISIBLE binding.btnAnonymous.visibility = View.VISIBLE
} }
//Initial status viewLifecycleOwner.lifecycleScope.launch {
updateStatus(getString(R.string.session_init)) viewModel.authState.collectLatest {
when (it) {
AuthState.Init -> updateStatus(getString(R.string.session_init))
viewModel.liveData.observe(viewLifecycleOwner) { AuthState.Fetching -> {
when (it) { updateStatus(getString(R.string.requesting_new_session))
AuthState.Fetching -> {
updateStatus(getString(R.string.requesting_new_session))
}
AuthState.Valid -> {
val packageName = getPackageName()
if (packageName.isBlank()) {
navigateToDefaultTab()
} else {
requireArguments().remove("packageName")
findNavController().navigate(
SplashFragmentDirections.actionSplashFragmentToAppDetailsFragment(
packageName
)
)
} }
}
AuthState.Available -> { AuthState.Valid -> {
updateStatus(getString(R.string.session_verifying)) val packageName = getPackageName()
updateActionLayout(false) if (packageName.isBlank()) {
} navigateToDefaultTab()
} else {
AuthState.Unavailable -> { requireArguments().remove("packageName")
updateStatus(getString(R.string.session_login)) findNavController().navigate(
updateActionLayout(true) SplashFragmentDirections.actionSplashFragmentToAppDetailsFragment(
} packageName
)
AuthState.SignedIn -> {
val packageName = getPackageName()
if (packageName.isBlank()) {
navigateToDefaultTab()
} else {
requireArguments().remove("packageName")
findNavController().navigate(
SplashFragmentDirections.actionSplashFragmentToAppDetailsFragment(
packageName
) )
) }
} }
}
AuthState.SignedOut -> { AuthState.Available -> {
updateStatus(getString(R.string.session_scrapped)) updateStatus(getString(R.string.session_verifying))
updateActionLayout(true) updateActionLayout(false)
} }
AuthState.Verifying -> { AuthState.Unavailable -> {
updateStatus(getString(R.string.verifying_new_session)) updateStatus(getString(R.string.session_login))
} updateActionLayout(true)
}
is AuthState.Failed -> { AuthState.SignedIn -> {
updateStatus(it.status) val packageName = getPackageName()
updateActionLayout(true) if (packageName.isBlank()) {
resetActions() navigateToDefaultTab()
} else {
requireArguments().remove("packageName")
findNavController().navigate(
SplashFragmentDirections.actionSplashFragmentToAppDetailsFragment(
packageName
)
)
}
}
AuthState.SignedOut -> {
updateStatus(getString(R.string.session_scrapped))
updateActionLayout(true)
}
AuthState.Verifying -> {
updateStatus(getString(R.string.verifying_new_session))
}
is AuthState.Failed -> {
updateStatus(it.status)
updateActionLayout(true)
resetActions()
}
} }
} }
} }
// Check authentication status
viewModel.observe()
} }
private fun updateStatus(string: String?) { private fun updateStatus(string: String?) {
@@ -167,14 +168,14 @@ class SplashFragment : BaseFragment<FragmentSplashBinding>() {
private fun attachActions() { private fun attachActions() {
binding.btnAnonymous.addOnClickListener { binding.btnAnonymous.addOnClickListener {
if (viewModel.liveData.value != AuthState.Fetching) { if (viewModel.authState.value != AuthState.Fetching) {
binding.btnAnonymous.updateProgress(true) binding.btnAnonymous.updateProgress(true)
viewModel.buildAnonymousAuthData() viewModel.buildAnonymousAuthData()
} }
} }
binding.btnGoogle.addOnClickListener { binding.btnGoogle.addOnClickListener {
if (viewModel.liveData.value != AuthState.Fetching) { if (viewModel.authState.value != AuthState.Fetching) {
binding.btnGoogle.updateProgress(true) binding.btnGoogle.updateProgress(true)
findNavController().navigate(R.id.googleFragment) findNavController().navigate(R.id.googleFragment)
} }

View File

@@ -22,7 +22,6 @@ package com.aurora.store.viewmodel.auth
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.aurora.Constants import com.aurora.Constants
@@ -40,6 +39,8 @@ import com.aurora.store.util.Preferences
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.net.ConnectException import java.net.ConnectException
import java.net.UnknownHostException import java.net.UnknownHostException
@@ -55,21 +56,15 @@ class AuthViewModel @Inject constructor(
private val TAG = AuthViewModel::class.java.simpleName private val TAG = AuthViewModel::class.java.simpleName
val liveData: MutableLiveData<AuthState> = MutableLiveData() private val _authState: MutableStateFlow<AuthState> = MutableStateFlow(AuthState.Init)
val authState = _authState.asStateFlow()
fun observe() { init {
if (liveData.value != AuthState.Fetching) { updateAuthState()
if (AccountProvider.isLoggedIn(context)) {
liveData.postValue(AuthState.Available)
buildSavedAuthData()
} else {
liveData.postValue(AuthState.Unavailable)
}
}
} }
fun buildGoogleAuthData(email: String, token: String, tokenType: AuthHelper.Token) { fun buildGoogleAuthData(email: String, token: String, tokenType: AuthHelper.Token) {
liveData.postValue(AuthState.Fetching) _authState.value = AuthState.Fetching
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
verifyAndSaveAuth( verifyAndSaveAuth(
@@ -77,16 +72,15 @@ class AuthViewModel @Inject constructor(
AccountType.GOOGLE AccountType.GOOGLE
) )
} catch (exception: Exception) { } catch (exception: Exception) {
liveData.postValue( _authState.value =
AuthState.Failed(context.getString(R.string.failed_to_generate_session)) AuthState.Failed(context.getString(R.string.failed_to_generate_session))
)
Log.e(TAG, "Failed to generate Session", exception) Log.e(TAG, "Failed to generate Session", exception)
} }
} }
} }
fun buildAnonymousAuthData() { fun buildAnonymousAuthData() {
liveData.postValue(AuthState.Fetching) _authState.value = AuthState.Fetching
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
verifyAndSaveAuth( verifyAndSaveAuth(
@@ -95,7 +89,7 @@ class AuthViewModel @Inject constructor(
) )
} catch (exception: Exception) { } catch (exception: Exception) {
Log.e(TAG, "Failed to generate Session", exception) Log.e(TAG, "Failed to generate Session", exception)
liveData.postValue(AuthState.Failed(exception.message.toString())) _authState.value = AuthState.Failed(exception.message.toString())
} }
} }
} }
@@ -125,11 +119,22 @@ class AuthViewModel @Inject constructor(
} }
} }
private fun updateAuthState() {
if (_authState.value != AuthState.Fetching) {
if (AccountProvider.isLoggedIn(context)) {
_authState.value = AuthState.Available
buildSavedAuthData()
} else {
_authState.value = AuthState.Unavailable
}
}
}
private fun buildSavedAuthData() { private fun buildSavedAuthData() {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
if (authProvider.isSavedAuthDataValid()) { if (authProvider.isSavedAuthDataValid()) {
liveData.postValue(AuthState.Valid) _authState.value = AuthState.Valid
} else { } else {
// Generate and validate new auth // Generate and validate new auth
when (AccountProvider.getAccountType(context)) { when (AccountProvider.getAccountType(context)) {
@@ -152,13 +157,13 @@ class AuthViewModel @Inject constructor(
is ConnectException -> context.getString(R.string.server_unreachable) is ConnectException -> context.getString(R.string.server_unreachable)
else -> context.getString(R.string.bad_request) else -> context.getString(R.string.bad_request)
} }
liveData.postValue(AuthState.Failed(error)) _authState.value = AuthState.Failed(error)
} }
} }
} }
private fun verifyAndSaveAuth(authData: AuthData, accountType: AccountType) { private fun verifyAndSaveAuth(authData: AuthData, accountType: AccountType) {
liveData.postValue(AuthState.Verifying) _authState.value = AuthState.Verifying
if (authData.authToken.isNotEmpty() && authData.deviceConfigToken.isNotEmpty()) { if (authData.authToken.isNotEmpty() && authData.deviceConfigToken.isNotEmpty()) {
authProvider.saveAuthData(authData) authProvider.saveAuthData(authData)
AccountProvider.login( AccountProvider.login(
@@ -168,13 +173,12 @@ class AuthViewModel @Inject constructor(
if (authData.aasToken.isBlank()) AuthHelper.Token.AUTH else AuthHelper.Token.AAS, if (authData.aasToken.isBlank()) AuthHelper.Token.AUTH else AuthHelper.Token.AAS,
accountType accountType
) )
liveData.postValue(AuthState.SignedIn) _authState.value = AuthState.SignedIn
} else { } else {
authProvider.removeAuthData(context) authProvider.removeAuthData(context)
AccountProvider.logout(context) AccountProvider.logout(context)
liveData.postValue( _authState.value =
AuthState.Failed(context.getString(R.string.failed_to_generate_session)) AuthState.Failed(context.getString(R.string.failed_to_generate_session))
)
} }
} }
} }