PM-26910: Minor UI updates for the Authenticator (#6028)

This commit is contained in:
David Perez 2025-10-14 14:59:08 -05:00 committed by GitHub
parent e7365b355f
commit 5b5176db40
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 56 additions and 115 deletions

View File

@ -2,28 +2,21 @@ package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting
import android.Manifest import android.Manifest
import android.widget.Toast import android.widget.Toast
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
@ -64,9 +57,8 @@ import com.bitwarden.ui.platform.base.util.toListItemCardStyle
import com.bitwarden.ui.platform.components.appbar.BitwardenMediumTopAppBar import com.bitwarden.ui.platform.components.appbar.BitwardenMediumTopAppBar
import com.bitwarden.ui.platform.components.appbar.action.BitwardenSearchActionItem import com.bitwarden.ui.platform.components.appbar.action.BitwardenSearchActionItem
import com.bitwarden.ui.platform.components.button.BitwardenFilledButton import com.bitwarden.ui.platform.components.button.BitwardenFilledButton
import com.bitwarden.ui.platform.components.button.BitwardenTextButton import com.bitwarden.ui.platform.components.button.model.BitwardenButtonData
import com.bitwarden.ui.platform.components.card.BitwardenActionCard import com.bitwarden.ui.platform.components.card.BitwardenActionCard
import com.bitwarden.ui.platform.components.card.color.bitwardenCardColors
import com.bitwarden.ui.platform.components.content.BitwardenLoadingContent import com.bitwarden.ui.platform.components.content.BitwardenLoadingContent
import com.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog import com.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog
import com.bitwarden.ui.platform.components.dialog.BitwardenLoadingDialog import com.bitwarden.ui.platform.components.dialog.BitwardenLoadingDialog
@ -213,7 +205,7 @@ fun ItemListingScreen(
), ),
expandableFabIcon = ExpandableFabIcon( expandableFabIcon = ExpandableFabIcon(
icon = IconData.Local( icon = IconData.Local(
iconRes = BitwardenDrawable.ic_plus, iconRes = BitwardenDrawable.ic_plus_large,
contentDescription = BitwardenString.add_item.asText(), contentDescription = BitwardenString.add_item.asText(),
testTag = "AddItemButton", testTag = "AddItemButton",
), ),
@ -619,102 +611,6 @@ fun EmptyItemListingContent(
} }
} }
@Composable
private fun DownloadBitwardenActionCard(
onDismissClick: () -> Unit,
onDownloadBitwardenClick: () -> Unit,
modifier: Modifier = Modifier,
) = BitwardenActionCard(
modifier = modifier,
cardSubtitle = stringResource(BitwardenString.download_bitwarden_card_message),
actionText = stringResource(BitwardenString.download_now),
cardTitle = stringResource(BitwardenString.download_bitwarden_card_title),
onActionClick = onDownloadBitwardenClick,
leadingContent = {
Icon(
painter = rememberVectorPainter(BitwardenDrawable.ic_shield),
contentDescription = null,
tint = BitwardenTheme.colorScheme.icon.secondary,
)
},
onDismissClick = onDismissClick,
)
@Suppress("LongMethod")
@Composable
private fun SyncWithBitwardenActionCard(
onDismissClick: () -> Unit,
onAppSettingsClick: () -> Unit,
onLearnMoreClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Card(
modifier = modifier,
shape = BitwardenTheme.shapes.actionCard,
colors = bitwardenCardColors(),
elevation = CardDefaults.elevatedCardElevation(),
border = BorderStroke(width = 1.dp, color = BitwardenTheme.colorScheme.stroke.border),
) {
Spacer(Modifier.height(height = 4.dp))
Row(modifier = Modifier.fillMaxWidth()) {
Spacer(Modifier.width(width = 16.dp))
Row(
modifier = Modifier.padding(top = 12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = rememberVectorPainter(id = BitwardenDrawable.ic_shield),
contentDescription = null,
tint = BitwardenTheme.colorScheme.icon.secondary,
modifier = Modifier.size(size = 20.dp),
)
Spacer(Modifier.width(width = 16.dp))
Text(
text = stringResource(id = BitwardenString.sync_with_the_bitwarden_app),
style = BitwardenTheme.typography.bodyLarge,
color = BitwardenTheme.colorScheme.text.primary,
)
}
Spacer(Modifier.weight(weight = 1f))
Spacer(Modifier.width(width = 16.dp))
IconButton(onClick = onDismissClick) {
Icon(
painter = painterResource(id = BitwardenDrawable.ic_close),
contentDescription = stringResource(id = BitwardenString.close),
tint = BitwardenTheme.colorScheme.icon.primary,
modifier = Modifier.size(size = 24.dp),
)
}
Spacer(Modifier.width(width = 4.dp))
}
Text(
text = stringResource(id = BitwardenString.sync_with_bitwarden_action_card_message),
style = BitwardenTheme.typography.bodyMedium,
color = BitwardenTheme.colorScheme.text.primary,
modifier = Modifier
.padding(horizontal = 16.dp)
.padding(start = 36.dp, end = 48.dp)
.fillMaxWidth(),
)
Spacer(Modifier.height(height = 16.dp))
BitwardenFilledButton(
label = stringResource(id = BitwardenString.take_me_to_app_settings),
onClick = onAppSettingsClick,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
BitwardenTextButton(
label = stringResource(id = BitwardenString.learn_more),
onClick = onLearnMoreClick,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
Spacer(Modifier.height(height = 4.dp))
}
}
@Composable @Composable
private fun ActionCard( private fun ActionCard(
actionCardState: ItemListingState.ActionCardState, actionCardState: ItemListingState.ActionCardState,
@ -727,19 +623,44 @@ private fun ActionCard(
) { ) {
when (actionCardState) { when (actionCardState) {
ItemListingState.ActionCardState.DownloadBitwardenApp -> { ItemListingState.ActionCardState.DownloadBitwardenApp -> {
DownloadBitwardenActionCard( BitwardenActionCard(
modifier = modifier, modifier = modifier,
onDownloadBitwardenClick = onDownloadBitwardenClick, cardSubtitle = stringResource(id = BitwardenString.download_bitwarden_card_message),
actionText = stringResource(id = BitwardenString.download_now),
cardTitle = stringResource(id = BitwardenString.download_bitwarden_card_title),
onActionClick = onDownloadBitwardenClick,
onDismissClick = onDownloadBitwardenDismissClick, onDismissClick = onDownloadBitwardenDismissClick,
leadingContent = {
Icon(
painter = rememberVectorPainter(id = BitwardenDrawable.ic_shield),
contentDescription = null,
tint = BitwardenTheme.colorScheme.icon.secondary,
)
},
) )
} }
ItemListingState.ActionCardState.SyncWithBitwarden -> { ItemListingState.ActionCardState.SyncWithBitwarden -> {
SyncWithBitwardenActionCard( BitwardenActionCard(
modifier = modifier, modifier = modifier,
onAppSettingsClick = onSyncWithBitwardenClick, cardTitle = stringResource(id = BitwardenString.sync_with_the_bitwarden_app),
actionText = stringResource(id = BitwardenString.take_me_to_app_settings),
onActionClick = onSyncWithBitwardenClick,
cardSubtitle = stringResource(
id = BitwardenString.sync_with_bitwarden_action_card_message,
),
onDismissClick = onSyncWithBitwardenDismissClick, onDismissClick = onSyncWithBitwardenDismissClick,
onLearnMoreClick = onSyncLearnMoreClick, secondaryButton = BitwardenButtonData(
label = BitwardenString.learn_more.asText(),
onClick = onSyncLearnMoreClick,
),
leadingContent = {
Icon(
painter = rememberVectorPainter(id = BitwardenDrawable.ic_refresh),
contentDescription = null,
tint = BitwardenTheme.colorScheme.icon.secondary,
)
},
) )
} }

View File

@ -26,15 +26,19 @@ import androidx.compose.ui.layout.positionInParent
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.bitwarden.ui.platform.base.util.nullableTestTag
import com.bitwarden.ui.platform.base.util.toDp import com.bitwarden.ui.platform.base.util.toDp
import com.bitwarden.ui.platform.components.badge.NotificationBadge import com.bitwarden.ui.platform.components.badge.NotificationBadge
import com.bitwarden.ui.platform.components.button.BitwardenFilledButton import com.bitwarden.ui.platform.components.button.BitwardenFilledButton
import com.bitwarden.ui.platform.components.button.BitwardenStandardIconButton import com.bitwarden.ui.platform.components.button.BitwardenStandardIconButton
import com.bitwarden.ui.platform.components.button.BitwardenTextButton
import com.bitwarden.ui.platform.components.button.model.BitwardenButtonData
import com.bitwarden.ui.platform.components.card.color.bitwardenCardColors import com.bitwarden.ui.platform.components.card.color.bitwardenCardColors
import com.bitwarden.ui.platform.components.util.rememberVectorPainter import com.bitwarden.ui.platform.components.util.rememberVectorPainter
import com.bitwarden.ui.platform.resource.BitwardenDrawable import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.resource.BitwardenString import com.bitwarden.ui.platform.resource.BitwardenString
import com.bitwarden.ui.platform.theme.BitwardenTheme import com.bitwarden.ui.platform.theme.BitwardenTheme
import com.bitwarden.ui.util.asText
/** /**
* A design component action card, which contains a title, action button, and a dismiss button * A design component action card, which contains a title, action button, and a dismiss button
@ -44,8 +48,9 @@ import com.bitwarden.ui.platform.theme.BitwardenTheme
* @param actionText The text content on the CTA button. * @param actionText The text content on the CTA button.
* @param onActionClick The action to perform when the CTA button is clicked. * @param onActionClick The action to perform when the CTA button is clicked.
* @param onDismissClick Optional action to perform when the dismiss button is clicked. * @param onDismissClick Optional action to perform when the dismiss button is clicked.
* @param leadingContent Optional content to display on the leading side of the * @param cardSubtitle The subtitle of the card.
* [cardTitle] [Text]. * @param secondaryButton The optional data for a secondary button.
* @param leadingContent Optional content to display on the leading side of the [cardTitle] [Text].
*/ */
@Suppress("LongMethod") @Suppress("LongMethod")
@Composable @Composable
@ -56,6 +61,7 @@ fun BitwardenActionCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onDismissClick: (() -> Unit)? = null, onDismissClick: (() -> Unit)? = null,
cardSubtitle: String? = null, cardSubtitle: String? = null,
secondaryButton: BitwardenButtonData? = null,
leadingContent: @Composable (() -> Unit)? = null, leadingContent: @Composable (() -> Unit)? = null,
) { ) {
Card( Card(
@ -132,6 +138,16 @@ fun BitwardenActionCard(
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
.fillMaxWidth(), .fillMaxWidth(),
) )
secondaryButton?.let {
BitwardenTextButton(
label = it.label(),
onClick = it.onClick,
modifier = Modifier
.padding(horizontal = 16.dp)
.nullableTestTag(tag = it.testTag)
.fillMaxWidth(),
)
}
Spacer(modifier = Modifier.height(height = 16.dp)) Spacer(modifier = Modifier.height(height = 16.dp))
} }
} }
@ -199,6 +215,10 @@ private fun BitwardenActionCardWithSubtitle_preview() {
actionText = "Action", actionText = "Action",
onActionClick = {}, onActionClick = {},
onDismissClick = {}, onDismissClick = {},
secondaryButton = BitwardenButtonData(
label = "Learn More".asText(),
onClick = {},
),
leadingContent = { leadingContent = {
NotificationBadge( NotificationBadge(
notificationCount = 1, notificationCount = 1,

View File

@ -97,7 +97,7 @@ fun BitwardenExpandableFloatingActionButton(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.End, horizontalAlignment = Alignment.End,
verticalArrangement = Arrangement.spacedBy( verticalArrangement = Arrangement.spacedBy(
space = 12.dp, space = 8.dp,
alignment = Alignment.Bottom, alignment = Alignment.Bottom,
), ),
contentPadding = PaddingValues(bottom = 16.dp), contentPadding = PaddingValues(bottom = 16.dp),
@ -167,7 +167,7 @@ private fun ExpandableFabOption(
) { ) {
Text( Text(
text = expandableFabOption.label(), text = expandableFabOption.label(),
style = BitwardenTheme.typography.labelSmall, style = BitwardenTheme.typography.labelLarge,
modifier = Modifier.padding(all = 8.dp), modifier = Modifier.padding(all = 8.dp),
) )
Icon( Icon(