PM-13286: Update segmented control to match the TopAppBar (#4058)

This commit is contained in:
David Perez 2024-10-10 16:14:13 -05:00 committed by GitHub
parent 3e9e45ba2f
commit c3af26d83f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 69 additions and 60 deletions

View file

@ -1,14 +1,21 @@
package com.x8bit.bitwarden.ui.platform.components.segment
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.unit.dp
import com.x8bit.bitwarden.ui.platform.components.segment.color.bitwardenSegmentedButtonColors
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
import kotlinx.collections.immutable.ImmutableList
/**
@ -22,21 +29,40 @@ fun BitwardenSegmentedButton(
options: ImmutableList<SegmentedButtonState>,
modifier: Modifier = Modifier,
) {
SingleChoiceSegmentedButtonRow(
modifier = modifier,
Box(
modifier = modifier
.background(color = BitwardenTheme.colorScheme.background.secondary)
.padding(top = 4.dp, bottom = 8.dp, start = 16.dp, end = 16.dp),
) {
options.forEachIndexed { index, option ->
SegmentedButton(
selected = option.isChecked,
onClick = option.onClick,
colors = bitwardenSegmentedButtonColors(),
shape = SegmentedButtonDefaults.itemShape(
index = index,
count = options.size,
),
label = { Text(text = option.text) },
modifier = Modifier.semantics { option.testTag?.let { testTag = it } },
)
SingleChoiceSegmentedButtonRow(
modifier = Modifier
.fillMaxWidth()
.background(
color = BitwardenTheme.colorScheme.background.primary,
shape = BitwardenTheme.shapes.segmentedControl,
)
.padding(horizontal = 4.dp),
space = 0.dp,
) {
options.forEachIndexed { index, option ->
SegmentedButton(
selected = option.isChecked,
onClick = option.onClick,
colors = bitwardenSegmentedButtonColors(),
shape = BitwardenTheme.shapes.segmentedControl,
border = BorderStroke(width = 0.dp, color = Color.Transparent),
label = {
Text(
text = option.text,
style = BitwardenTheme.typography.labelLarge,
)
},
icon = {
// No icon required
},
modifier = Modifier.semantics { option.testTag?.let { testTag = it } },
)
}
}
}
}

View file

@ -2,6 +2,7 @@ package com.x8bit.bitwarden.ui.platform.components.segment.color
import androidx.compose.material3.SegmentedButtonColors
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
/**
@ -11,14 +12,14 @@ import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
fun bitwardenSegmentedButtonColors(): SegmentedButtonColors = SegmentedButtonColors(
activeContainerColor = BitwardenTheme.colorScheme.filledButton.backgroundReversed,
activeContentColor = BitwardenTheme.colorScheme.filledButton.foregroundReversed,
activeBorderColor = BitwardenTheme.colorScheme.stroke.divider,
activeBorderColor = Color.Transparent,
inactiveContainerColor = BitwardenTheme.colorScheme.background.primary,
inactiveContentColor = BitwardenTheme.colorScheme.text.secondary,
inactiveBorderColor = BitwardenTheme.colorScheme.stroke.divider,
inactiveBorderColor = Color.Transparent,
disabledActiveContainerColor = BitwardenTheme.colorScheme.background.primary,
disabledActiveContentColor = BitwardenTheme.colorScheme.filledButton.foregroundDisabled,
disabledActiveBorderColor = BitwardenTheme.colorScheme.stroke.divider,
disabledActiveBorderColor = Color.Transparent,
disabledInactiveContainerColor = BitwardenTheme.colorScheme.background.primary,
disabledInactiveContentColor = BitwardenTheme.colorScheme.filledButton.foregroundDisabled,
disabledInactiveBorderColor = BitwardenTheme.colorScheme.stroke.divider,
disabledInactiveBorderColor = Color.Transparent,
)

View file

@ -16,5 +16,6 @@ data class BitwardenShapes(
val dialog: CornerBasedShape,
val infoCallout: CornerBasedShape,
val menu: CornerBasedShape,
val segmentedControl: CornerBasedShape,
val snackbar: CornerBasedShape,
)

View file

@ -1,5 +1,6 @@
package com.x8bit.bitwarden.ui.platform.theme.shape
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.unit.dp
@ -15,5 +16,6 @@ val bitwardenShapes: BitwardenShapes = BitwardenShapes(
dialog = RoundedCornerShape(size = 28.dp),
infoCallout = RoundedCornerShape(size = 8.dp),
menu = RoundedCornerShape(size = 4.dp),
segmentedControl = CircleShape,
snackbar = RoundedCornerShape(size = 8.dp),
)

View file

@ -72,6 +72,26 @@ fun AddSendContent(
modifier = modifier
.verticalScroll(rememberScrollState()),
) {
if (isAddMode && !isShared) {
BitwardenSegmentedButton(
modifier = Modifier.fillMaxWidth(),
options = persistentListOf(
SegmentedButtonState(
text = stringResource(id = R.string.file),
onClick = addSendHandlers.onFileTypeSelect,
isChecked = state.isFileType,
testTag = "SendFileButton",
),
SegmentedButtonState(
text = stringResource(id = R.string.text),
onClick = addSendHandlers.onTextTypeSelect,
isChecked = state.isTextType,
testTag = "SendTextButton",
),
),
)
}
if (policyDisablesSend) {
BitwardenInfoCalloutCard(
text = stringResource(id = R.string.send_disabled_warning),
@ -106,37 +126,6 @@ fun AddSendContent(
onValueChange = addSendHandlers.onNamChange,
)
if (isAddMode && !isShared) {
Spacer(modifier = Modifier.height(16.dp))
BitwardenListHeaderText(
label = stringResource(id = R.string.type),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
)
Spacer(modifier = Modifier.height(16.dp))
BitwardenSegmentedButton(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
options = persistentListOf(
SegmentedButtonState(
text = stringResource(id = R.string.file),
onClick = addSendHandlers.onFileTypeSelect,
isChecked = state.isFileType,
testTag = "SendFileButton",
),
SegmentedButtonState(
text = stringResource(id = R.string.text),
onClick = addSendHandlers.onTextTypeSelect,
isChecked = state.isTextType,
testTag = "SendTextButton",
),
),
)
}
Spacer(modifier = Modifier.height(8.dp))
when (val type = state.selectedType) {
is AddSendState.ViewState.Content.SendType.File -> {

View file

@ -358,9 +358,6 @@ class AddSendScreenTest : BaseComposeTest() {
@Test
fun `segmented buttons should appear based on state`() {
mutableStateFlow.update { it.copy(isShared = true) }
composeTestRule
.onNodeWithText("Type")
.assertDoesNotExist()
composeTestRule
.onAllNodesWithText("File")
.filterToOne(!isEditableText)
@ -376,10 +373,6 @@ class AddSendScreenTest : BaseComposeTest() {
addSendType = AddSendType.AddItem,
)
}
composeTestRule
.onNodeWithText("Type")
.performScrollTo()
.assertIsDisplayed()
composeTestRule
.onAllNodesWithText("File")
.filterToOne(!isEditableText)
@ -395,9 +388,6 @@ class AddSendScreenTest : BaseComposeTest() {
it.copy(addSendType = AddSendType.EditItem(sendItemId = "sendId"))
}
composeTestRule
.onNodeWithText("Type")
.assertIsNotDisplayed()
composeTestRule
.onAllNodesWithText("File")
.filterToOne(!isEditableText)