mirror of
https://github.com/bitwarden/android.git
synced 2025-02-16 11:59:57 +03:00
BIT-994 Use dialogs instead of dropdowns on generator (#188)
This commit is contained in:
parent
cb2c6495c8
commit
1873ffe985
2 changed files with 36 additions and 42 deletions
|
@ -4,25 +4,17 @@ import androidx.compose.foundation.clickable
|
|||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
|
@ -31,7 +23,7 @@ import androidx.compose.ui.semantics.role
|
|||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toDp
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
|
||||
/**
|
||||
|
@ -41,7 +33,7 @@ import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
|||
* When the field is clicked, a dropdown menu appears with a list of options to select from.
|
||||
*
|
||||
* @param label The descriptive text label for the [OutlinedTextField].
|
||||
* @param options A list of strings representing the available options in the dropdown menu.
|
||||
* @param options A list of strings representing the available options in the dialog.
|
||||
* @param selectedOption The currently selected option that is displayed in the [OutlinedTextField].
|
||||
* @param onOptionSelected A lambda that is invoked when an option
|
||||
* is selected from the dropdown menu.
|
||||
|
@ -56,14 +48,7 @@ fun BitwardenMultiSelectButton(
|
|||
onOptionSelected: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
var textFieldWidth by remember { mutableIntStateOf(0) }
|
||||
|
||||
// Watch for changes to 'expanded' and request focus if needed
|
||||
LaunchedEffect(expanded) {
|
||||
if (expanded) focusRequester.requestFocus() else focusRequester.freeFocus()
|
||||
}
|
||||
var shouldShowDialog by remember { mutableStateOf(false) }
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
|
@ -82,12 +67,8 @@ fun BitwardenMultiSelectButton(
|
|||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
) {
|
||||
expanded = !expanded
|
||||
}
|
||||
.onGloballyPositioned { coordinates ->
|
||||
textFieldWidth = coordinates.size.width
|
||||
}
|
||||
.focusRequester(focusRequester),
|
||||
shouldShowDialog = !shouldShowDialog
|
||||
},
|
||||
textStyle = MaterialTheme.typography.bodyLarge,
|
||||
readOnly = true,
|
||||
label = {
|
||||
|
@ -97,7 +78,7 @@ fun BitwardenMultiSelectButton(
|
|||
},
|
||||
value = selectedOption,
|
||||
onValueChange = onOptionSelected,
|
||||
enabled = expanded,
|
||||
enabled = shouldShowDialog,
|
||||
trailingIcon = {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_region_select_dropdown),
|
||||
|
@ -114,23 +95,21 @@ fun BitwardenMultiSelectButton(
|
|||
disabledPlaceholderColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
DropdownMenu(
|
||||
modifier = Modifier.width(textFieldWidth.toDp()),
|
||||
expanded = expanded,
|
||||
onDismissRequest = {
|
||||
expanded = false
|
||||
focusRequester.freeFocus()
|
||||
},
|
||||
) {
|
||||
options.forEach { optionString ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = optionString) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
onOptionSelected(optionString)
|
||||
focusRequester.freeFocus()
|
||||
},
|
||||
)
|
||||
if (shouldShowDialog) {
|
||||
BitwardenSelectionDialog(
|
||||
title = label.asText(),
|
||||
onDismissRequest = { shouldShowDialog = false },
|
||||
) {
|
||||
options.forEach { optionString ->
|
||||
BitwardenSelectionRow(
|
||||
text = optionString.asText(),
|
||||
isSelected = optionString == selectedOption,
|
||||
onClick = {
|
||||
shouldShowDialog = false
|
||||
onOptionSelected(optionString)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,15 @@ package com.x8bit.bitwarden.ui.tools.feature.generator
|
|||
import androidx.compose.ui.semantics.ProgressBarRangeInfo
|
||||
import androidx.compose.ui.semantics.SemanticsProperties
|
||||
import androidx.compose.ui.test.SemanticsMatcher.Companion.expectValue
|
||||
import androidx.compose.ui.test.assert
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsOff
|
||||
import androidx.compose.ui.test.assertIsOn
|
||||
import androidx.compose.ui.test.filterToOne
|
||||
import androidx.compose.ui.test.hasAnyAncestor
|
||||
import androidx.compose.ui.test.hasContentDescription
|
||||
import androidx.compose.ui.test.hasProgressBarRangeInfo
|
||||
import androidx.compose.ui.test.isDialog
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onChildren
|
||||
import androidx.compose.ui.test.onLast
|
||||
|
@ -96,6 +99,7 @@ class GeneratorScreenTest : BaseComposeTest() {
|
|||
.onAllNodesWithText(text = "Password")
|
||||
.onLast()
|
||||
.performScrollTo()
|
||||
.assert(hasAnyAncestor(isDialog()))
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -103,6 +107,11 @@ class GeneratorScreenTest : BaseComposeTest() {
|
|||
GeneratorAction.MainTypeOptionSelect(GeneratorState.MainTypeOption.PASSWORD),
|
||||
)
|
||||
}
|
||||
|
||||
// Make sure dialog is hidden:
|
||||
composeTestRule
|
||||
.onNode(isDialog())
|
||||
.assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -120,6 +129,7 @@ class GeneratorScreenTest : BaseComposeTest() {
|
|||
composeTestRule
|
||||
.onAllNodesWithText(text = "Passphrase")
|
||||
.onLast()
|
||||
.assert(hasAnyAncestor(isDialog()))
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -129,6 +139,11 @@ class GeneratorScreenTest : BaseComposeTest() {
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
// Make sure dialog is hidden:
|
||||
composeTestRule
|
||||
.onNode(isDialog())
|
||||
.assertDoesNotExist()
|
||||
}
|
||||
|
||||
//region Passcode Password Tests
|
||||
|
|
Loading…
Add table
Reference in a new issue