Access the login state from every screen (Jetpack Compose + MVVM + Hilt)

Viewed 425

I try to access the login state and other user information everywhere in my app.

Here is how I plan on doing it:

Create a UserState data class:

data class UserState(
    val username: String = "",
    val profileImageUrl: String = "",
    var isLoggedIn: Boolean = false,
    val isPremiumUser: Boolean = false,
    val coins: Int = 0
)

Make it a singleton with hilt and inject it into my AuthRepository:

    @Provides
    @Singleton
    fun provideUserState() = UserState()

    @Singleton
    @Provides
    fun provideAuthRepository(userState: UserState): AuthRepository {
        return AuthRepositoryImpl(userState)
    }

then when the authentication (firebase + custom backend) is succesfull or other auth functions get called I update the userState with the userData:

class AuthRepositoryImpl @Inject constructor( 
    private var userState: UserState 
) : AuthRepository {

    override fun getUserState(): UserState {
        return userState
    }

    override suspend fun authenticateUser(token: String){
        
        val responseUser = authenticateUser(token)
        if (responseUser != null) {
            userState = UserState(
                username = responseUser.username,
                profileImageUrl = responseUser.profileImageUrl,
                isLoggedIn = true,
                isPremiumUser = responseUser.profileImageUrl,
                coins = responseUser.coins
            )
        } 
    } 
}

Now comes the part where I am not sure on how to do it, how do I observe the userState from my ViewModels? If I call for example the logOut function in my AuthRepository from ViewModel X I want to see/get the change in ViewModel Y.

I call the getUserState method for example in the init block of my MainViewModel:

init {
    _mainUserState.value = authRepository.getUserState()
}

So the problem is it only gets updated on the start, how can I observe changes that get made to the UserState Singleton? I'm not sure if flows are the answer and if yes how exactly to use them int his scenario

1 Answers

You can do something like this with flow in you'r auth repository:

private val _authData = MutableStateFlow<AuthEvent>(AuthEvent.Nothing)
    val authData: Flow<AuthEvent> = _authData

then emit like this when login/logout

_authData.emit(AuthEvent.Login)
  • AuthEvent is just a sealed class

  • Add the AuthState to AuthEvent.Login class

  • you can do shared flow too



then in you'r viewModel observe it under viewModelScope

viewModelScope.launch {
            authRepository.getAuthFlow().collect() { data ->
                when (data) {
                    is AuthEvent.Logout -> {
                        sendUiEvent(MainUIEvent.Logout)
                        _state.value = state.value.copy(isLoggedIn = false, authData = null)
                    }

                    is AuthEvent.Login -> {
                        _state.value = state.value.copy(isLoggedIn = true, authData = data.authData)
                        sendUiEvent(MainUIEvent.LoggedIn)
                    }

                    is AuthEvent.Nothing -> {

                    }
                }
            }
        }

this appoarch allows you to handle auth status and navigation from you mainViewModel

Related