Listen to UserState changes on the Vault Unlock screen (#290)

This commit is contained in:
Brian Yencho 2023-11-29 08:12:43 -06:00 committed by Álison Fernandes
parent f8f89a5903
commit d4d64c2a6d
2 changed files with 95 additions and 3 deletions

View file

@ -6,6 +6,7 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.auth.repository.model.UserState
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult
@ -65,6 +66,12 @@ class VaultUnlockViewModel @Inject constructor(
}
}
.launchIn(viewModelScope)
authRepository
.userStateFlow
.onEach {
sendAction(VaultUnlockAction.Internal.UserStateUpdateReceive(userState = it))
}
.launchIn(viewModelScope)
}
override fun handleAction(action: VaultUnlockAction) {
@ -78,6 +85,10 @@ class VaultUnlockViewModel @Inject constructor(
is VaultUnlockAction.Internal.ReceiveVaultUnlockResult -> {
handleReceiveVaultUnlockResult(action)
}
is VaultUnlockAction.Internal.UserStateUpdateReceive -> {
handleUserStateUpdateReceive(action)
}
}
}
@ -146,6 +157,24 @@ class VaultUnlockViewModel @Inject constructor(
}
}
}
private fun handleUserStateUpdateReceive(
action: VaultUnlockAction.Internal.UserStateUpdateReceive,
) {
// Leave the current data alone if there is no UserState; we are in the process of logging
// out.
val userState = action.userState ?: return
mutableStateFlow.update {
val accountSummaries = userState.toAccountSummaries()
val activeAccountSummary = userState.toActiveAccountSummary()
it.copy(
initials = activeAccountSummary.initials,
avatarColorString = activeAccountSummary.avatarColorHex,
accountSummaries = accountSummaries,
)
}
}
}
/**
@ -252,5 +281,12 @@ sealed class VaultUnlockAction {
data class ReceiveVaultUnlockResult(
val vaultUnlockResult: VaultUnlockResult,
) : Internal()
/**
* Indicates a change in user state has been received.
*/
data class UserStateUpdateReceive(
val userState: UserState?,
) : Internal()
}
}

View file

@ -28,9 +28,10 @@ import org.junit.jupiter.api.Test
class VaultUnlockViewModelTest : BaseViewModelTest() {
private val mutableUserStateFlow = MutableStateFlow<UserState?>(DEFAULT_USER_STATE)
private val environmentRepository = FakeEnvironmentRepository()
private val authRepository = mockk<AuthRepository>() {
every { userStateFlow } returns MutableStateFlow(DEFAULT_USER_STATE)
every { userStateFlow } returns mutableUserStateFlow
every { logout() } just runs
}
private val vaultRepository = mockk<VaultRepository>()
@ -44,8 +45,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
@Test
fun `initial state should be correct when set`() {
val state = DEFAULT_STATE.copy(
initials = "WB",
avatarColorString = "00FF00",
passwordInput = "pass",
)
val viewModel = createViewModel(state = state)
assertEquals(state, viewModel.stateFlow.value)
@ -64,6 +64,62 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
)
}
@Test
fun `UserState updates with a null value should do nothing`() {
val viewModel = createViewModel()
assertEquals(
DEFAULT_STATE,
viewModel.stateFlow.value,
)
mutableUserStateFlow.value = null
assertEquals(
DEFAULT_STATE,
viewModel.stateFlow.value,
)
}
@Test
fun `UserState updates with a non-null value update the account information in the state`() {
val viewModel = createViewModel()
assertEquals(
DEFAULT_STATE,
viewModel.stateFlow.value,
)
mutableUserStateFlow.value =
DEFAULT_USER_STATE.copy(
accounts = listOf(
UserState.Account(
userId = "activeUserId",
name = "Other User",
email = "active@bitwarden.com",
avatarColorHex = "#00aaaa",
isPremium = true,
isVaultUnlocked = true,
),
),
)
assertEquals(
DEFAULT_STATE.copy(
avatarColorString = "#00aaaa",
initials = "OU",
accountSummaries = listOf(
AccountSummary(
userId = "activeUserId",
name = "Other User",
email = "active@bitwarden.com",
avatarColorHex = "#00aaaa",
status = AccountSummary.Status.ACTIVE,
),
),
),
viewModel.stateFlow.value,
)
}
@Test
fun `on AddAccountClick should emit NavigateToLoginScreen`() = runTest {
val viewModel = createViewModel()