mirror of
https://github.com/bitwarden/android.git
synced 2026-03-11 12:44:17 -05:00
Add empty state for debug menu without feature flags (#5918)
This commit is contained in:
@@ -23,6 +23,7 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bitwarden.authenticator.ui.platform.components.appbar.AuthenticatorTopAppBar
|
||||
import com.bitwarden.authenticator.ui.platform.components.button.AuthenticatorFilledButton
|
||||
import com.bitwarden.authenticator.ui.platform.components.content.AuthenticatorErrorContent
|
||||
import com.bitwarden.authenticator.ui.platform.components.header.BitwardenListHeaderText
|
||||
import com.bitwarden.authenticator.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.bitwarden.authenticator.ui.platform.feature.debugmenu.components.ListItemContent
|
||||
@@ -74,12 +75,14 @@ fun DebugMenuScreen(
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(innerPadding),
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
if (state.featureFlags.isEmpty()) {
|
||||
AuthenticatorErrorContent(
|
||||
message = stringResource(id = BitwardenString.empty_item_list),
|
||||
modifier = Modifier
|
||||
.padding(paddingValues = innerPadding)
|
||||
.fillMaxSize(),
|
||||
)
|
||||
} else {
|
||||
FeatureFlagContent(
|
||||
featureFlagMap = state.featureFlags,
|
||||
onValueChange = remember(viewModel) {
|
||||
@@ -88,10 +91,11 @@ fun DebugMenuScreen(
|
||||
}
|
||||
},
|
||||
onResetValues = remember(viewModel) {
|
||||
{
|
||||
viewModel.trySendAction(DebugMenuAction.ResetFeatureFlagValues)
|
||||
}
|
||||
{ viewModel.trySendAction(DebugMenuAction.ResetFeatureFlagValues) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(paddingValues = innerPadding),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ import com.bitwarden.authenticator.data.platform.repository.DebugMenuRepository
|
||||
import com.bitwarden.core.data.manager.model.FlagKey
|
||||
import com.bitwarden.ui.platform.base.BaseViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import kotlinx.collections.immutable.toImmutableMap
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@@ -23,7 +26,7 @@ class DebugMenuViewModel @Inject constructor(
|
||||
featureFlagManager: FeatureFlagManager,
|
||||
private val debugMenuRepository: DebugMenuRepository,
|
||||
) : BaseViewModel<DebugMenuState, DebugMenuEvent, DebugMenuAction>(
|
||||
initialState = DebugMenuState(featureFlags = emptyMap()),
|
||||
initialState = DebugMenuState(featureFlags = persistentMapOf()),
|
||||
) {
|
||||
|
||||
private var featureFlagResetJob: Job? = null
|
||||
@@ -60,7 +63,7 @@ class DebugMenuViewModel @Inject constructor(
|
||||
|
||||
private fun handleUpdateFeatureFlagMap(action: DebugMenuAction.Internal.UpdateFeatureFlagMap) {
|
||||
mutableStateFlow.update {
|
||||
it.copy(featureFlags = action.newMap)
|
||||
it.copy(featureFlags = action.newMap.toImmutableMap())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +76,7 @@ class DebugMenuViewModel @Inject constructor(
|
||||
* State for the [DebugMenuViewModel]
|
||||
*/
|
||||
data class DebugMenuState(
|
||||
val featureFlags: Map<FlagKey<Any>, Any>,
|
||||
val featureFlags: ImmutableMap<FlagKey<Any>, Any>,
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,11 +17,11 @@ fun <T : Any> FlagKey<T>.ListItemContent(
|
||||
onValueChange: (key: FlagKey<T>, value: T) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) = when (val flagKey = this) {
|
||||
FlagKey.DummyBoolean,
|
||||
is FlagKey.DummyInt,
|
||||
FlagKey.DummyString,
|
||||
-> Unit
|
||||
|
||||
FlagKey.DummyBoolean,
|
||||
FlagKey.BitwardenAuthenticationEnabled,
|
||||
FlagKey.CipherKeyEncryption,
|
||||
FlagKey.CredentialExchangeProtocolExport,
|
||||
|
||||
@@ -10,7 +10,9 @@ import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@@ -18,7 +20,7 @@ import org.junit.Test
|
||||
class DebugMenuScreenTest : AuthenticatorComposeTest() {
|
||||
private var onNavigateBackCalled = false
|
||||
private val mutableEventFlow = bufferedMutableSharedFlow<DebugMenuEvent>()
|
||||
private val mutableStateFlow = MutableStateFlow(DebugMenuState(featureFlags = emptyMap()))
|
||||
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
|
||||
private val viewModel = mockk<DebugMenuViewModel>(relaxed = true) {
|
||||
every { stateFlow } returns mutableStateFlow
|
||||
every { eventFlow } returns mutableEventFlow
|
||||
@@ -51,43 +53,31 @@ class DebugMenuScreenTest : AuthenticatorComposeTest() {
|
||||
|
||||
@Test
|
||||
fun `feature flag content should not display if the state is empty`() {
|
||||
mutableStateFlow.update {
|
||||
DebugMenuState(featureFlags = persistentMapOf())
|
||||
}
|
||||
composeTestRule
|
||||
.onNodeWithText("Bitwarden authentication enabled", ignoreCase = true)
|
||||
.onNodeWithText(text = "dummy-boolean")
|
||||
.assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `feature flag content should display if the state is not empty`() {
|
||||
mutableStateFlow.tryEmit(
|
||||
DebugMenuState(
|
||||
featureFlags = mapOf(
|
||||
FlagKey.BitwardenAuthenticationEnabled to true,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Bitwarden authentication enabled", ignoreCase = true)
|
||||
.onNodeWithText(text = "dummy-boolean")
|
||||
.assertExists()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `boolean feature flag content should send action when clicked`() {
|
||||
mutableStateFlow.tryEmit(
|
||||
DebugMenuState(
|
||||
featureFlags = mapOf(
|
||||
FlagKey.BitwardenAuthenticationEnabled to true,
|
||||
),
|
||||
),
|
||||
)
|
||||
composeTestRule
|
||||
.onNodeWithText("Bitwarden authentication enabled", ignoreCase = true)
|
||||
.onNodeWithText(text = "dummy-boolean")
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
viewModel.trySendAction(
|
||||
DebugMenuAction.UpdateFeatureFlag(
|
||||
FlagKey.BitwardenAuthenticationEnabled,
|
||||
FlagKey.DummyBoolean,
|
||||
false,
|
||||
),
|
||||
)
|
||||
@@ -104,3 +94,9 @@ class DebugMenuScreenTest : AuthenticatorComposeTest() {
|
||||
verify { viewModel.trySendAction(DebugMenuAction.ResetFeatureFlagValues) }
|
||||
}
|
||||
}
|
||||
|
||||
private val DEFAULT_STATE: DebugMenuState = DebugMenuState(
|
||||
featureFlags = persistentMapOf(
|
||||
FlagKey.DummyBoolean to true,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -12,6 +12,8 @@ import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import io.mockk.verify
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
@@ -77,11 +79,11 @@ class DebugMenuViewModelTest : BaseViewModelTest() {
|
||||
)
|
||||
}
|
||||
|
||||
private val DEFAULT_MAP_VALUE: Map<FlagKey<Any>, Any> = mapOf(
|
||||
private val DEFAULT_MAP_VALUE: ImmutableMap<FlagKey<Any>, Any> = persistentMapOf(
|
||||
FlagKey.BitwardenAuthenticationEnabled to true,
|
||||
)
|
||||
|
||||
private val UPDATED_MAP_VALUE: Map<FlagKey<Any>, Any> = mapOf(
|
||||
private val UPDATED_MAP_VALUE: ImmutableMap<FlagKey<Any>, Any> = persistentMapOf(
|
||||
FlagKey.BitwardenAuthenticationEnabled to false,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user