PM-26579: Remove duplicated BitwardenScaffold from ItemListingScreen (#5978)

This commit is contained in:
David Perez 2025-10-07 12:04:32 -05:00 committed by GitHub
parent 7849bbbb0a
commit 202dd65229
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -27,7 +27,6 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -41,6 +40,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalResources
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -63,12 +63,12 @@ import com.bitwarden.ui.platform.base.util.EventsEffect
import com.bitwarden.ui.platform.base.util.standardHorizontalMargin
import com.bitwarden.ui.platform.base.util.toListItemCardStyle
import com.bitwarden.ui.platform.components.appbar.BitwardenMediumTopAppBar
import com.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
import com.bitwarden.ui.platform.components.appbar.action.BitwardenSearchActionItem
import com.bitwarden.ui.platform.components.button.BitwardenFilledButton
import com.bitwarden.ui.platform.components.button.BitwardenTextButton
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.dialog.BitwardenBasicDialog
import com.bitwarden.ui.platform.components.dialog.BitwardenLoadingDialog
import com.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
@ -107,6 +107,7 @@ fun ItemListingScreen(
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
val context = LocalContext.current
val resources = LocalResources.current
val launcher = permissionsManager.getLauncher { isGranted ->
if (isGranted) {
viewModel.trySendAction(ItemListingAction.ScanQrCodeClick)
@ -124,13 +125,7 @@ fun ItemListingScreen(
is ItemListingEvent.NavigateToQrCodeScanner -> onNavigateToQrCodeScanner()
is ItemListingEvent.NavigateToManualAddItem -> onNavigateToManualKeyEntry()
is ItemListingEvent.ShowToast -> {
Toast
.makeText(
context,
event.message(context.resources),
Toast.LENGTH_LONG,
)
.show()
Toast.makeText(context, event.message(resources), Toast.LENGTH_LONG).show()
}
is ItemListingEvent.NavigateToEditItem -> onNavigateToEditItemScreen(event.id)
@ -164,50 +159,76 @@ fun ItemListingScreen(
ItemListingDialogs(
dialog = state.dialog,
onDismissRequest = remember(viewModel) {
{
viewModel.trySendAction(
ItemListingAction.DialogDismiss,
)
}
{ viewModel.trySendAction(ItemListingAction.DialogDismiss) }
},
onConfirmDeleteClick = remember(viewModel) {
{ itemId ->
viewModel.trySendAction(
ItemListingAction.ConfirmDeleteClick(itemId = itemId),
)
}
{ viewModel.trySendAction(ItemListingAction.ConfirmDeleteClick(it)) }
},
)
BitwardenScaffold(
modifier = Modifier
.fillMaxSize()
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
BitwardenMediumTopAppBar(
title = stringResource(id = BitwardenString.verification_codes),
scrollBehavior = scrollBehavior,
actions = {
if (state.viewState is ItemListingState.ViewState.Content) {
BitwardenSearchActionItem(
contentDescription = stringResource(id = BitwardenString.search_codes),
onClick = onNavigateToSearch,
)
}
},
)
},
floatingActionButton = {
BitwardenExpandableFloatingActionButton(
modifier = Modifier.testTag("AddItemButton"),
items = persistentListOf(
ItemListingExpandableFabAction.ScanQrCode(
label = BitwardenString.scan_a_qr_code.asText(),
icon = IconData.Local(
iconRes = BitwardenDrawable.ic_camera_small,
contentDescription = BitwardenString.scan_a_qr_code.asText(),
testTag = "ScanQRCodeButton",
),
onScanQrCodeClick = remember(viewModel) {
{ launcher.launch(Manifest.permission.CAMERA) }
},
),
ItemListingExpandableFabAction.EnterSetupKey(
label = BitwardenString.enter_key_manually.asText(),
icon = IconData.Local(
iconRes = BitwardenDrawable.ic_lock_encrypted_small,
contentDescription = BitwardenString.enter_key_manually.asText(),
testTag = "EnterSetupKeyButton",
),
onEnterSetupKeyClick = remember(viewModel) {
{ viewModel.trySendAction(ItemListingAction.EnterSetupKeyClick) }
},
),
),
expandableFabIcon = ExpandableFabIcon(
icon = IconData.Local(
iconRes = BitwardenDrawable.ic_plus,
contentDescription = BitwardenString.add_item.asText(),
testTag = "AddItemButton",
),
iconRotation = 45f,
),
)
},
snackbarHost = { FirstTimeSyncSnackbarHost(state = snackbarHostState) },
) {
when (val currentState = state.viewState) {
is ItemListingState.ViewState.Content -> {
ItemListingContent(
state = currentState,
snackbarHostState = snackbarHostState,
scrollBehavior = scrollBehavior,
onNavigateToSearch = remember(viewModel) {
{
viewModel.trySendAction(
ItemListingAction.SearchClick,
)
}
},
onScanQrCodeClick = remember(viewModel) {
{
launcher.launch(Manifest.permission.CAMERA)
}
},
onEnterSetupKeyClick = remember(viewModel) {
{
viewModel.trySendAction(ItemListingAction.EnterSetupKeyClick)
}
},
onItemClick = remember(viewModel) {
{
viewModel.trySendAction(
ItemListingAction.ItemClick(it),
)
}
{ viewModel.trySendAction(ItemListingAction.ItemClick(it)) }
},
onDropdownMenuClick = remember(viewModel) {
{ action, item ->
@ -220,24 +241,16 @@ fun ItemListingScreen(
}
},
onDownloadBitwardenClick = remember(viewModel) {
{
viewModel.trySendAction(ItemListingAction.DownloadBitwardenClick)
}
{ viewModel.trySendAction(ItemListingAction.DownloadBitwardenClick) }
},
onDismissDownloadBitwardenClick = remember(viewModel) {
{
viewModel.trySendAction(ItemListingAction.DownloadBitwardenDismiss)
}
{ viewModel.trySendAction(ItemListingAction.DownloadBitwardenDismiss) }
},
onSyncWithBitwardenClick = remember(viewModel) {
{
viewModel.trySendAction(ItemListingAction.SyncWithBitwardenClick)
}
{ viewModel.trySendAction(ItemListingAction.SyncWithBitwardenClick) }
},
onDismissSyncWithBitwardenClick = remember(viewModel) {
{
viewModel.trySendAction(ItemListingAction.SyncWithBitwardenDismiss)
}
{ viewModel.trySendAction(ItemListingAction.SyncWithBitwardenDismiss) }
},
onSyncLearnMoreClick = remember(viewModel) {
{ viewModel.trySendAction(ItemListingAction.SyncLearnMoreClick) }
@ -248,55 +261,37 @@ fun ItemListingScreen(
)
}
ItemListingState.ViewState.Loading -> Unit
is ItemListingState.ViewState.NoItems,
-> {
ItemListingState.ViewState.Loading -> {
BitwardenLoadingContent(modifier = Modifier.fillMaxSize())
}
is ItemListingState.ViewState.NoItems -> {
EmptyItemListingContent(
actionCardState = currentState.actionCard,
appTheme = state.appTheme,
scrollBehavior = scrollBehavior,
onAddCodeClick = remember(viewModel) {
{
launcher.launch(Manifest.permission.CAMERA)
}
},
onScanQrCodeClick = remember(viewModel) {
{
launcher.launch(Manifest.permission.CAMERA)
}
},
onEnterSetupKeyClick = remember(viewModel) {
{
viewModel.trySendAction(ItemListingAction.EnterSetupKeyClick)
}
{ launcher.launch(Manifest.permission.CAMERA) }
},
onDownloadBitwardenClick = remember(viewModel) {
{
viewModel.trySendAction(ItemListingAction.DownloadBitwardenClick)
}
{ viewModel.trySendAction(ItemListingAction.DownloadBitwardenClick) }
},
onDismissDownloadBitwardenClick = remember(viewModel) {
{
viewModel.trySendAction(ItemListingAction.DownloadBitwardenDismiss)
}
{ viewModel.trySendAction(ItemListingAction.DownloadBitwardenDismiss) }
},
onSyncWithBitwardenClick = remember(viewModel) {
{
viewModel.trySendAction(ItemListingAction.SyncWithBitwardenClick)
}
{ viewModel.trySendAction(ItemListingAction.SyncWithBitwardenClick) }
},
onSyncLearnMoreClick = remember(viewModel) {
{ viewModel.trySendAction(ItemListingAction.SyncLearnMoreClick) }
},
onDismissSyncWithBitwardenClick = remember(viewModel) {
{
viewModel.trySendAction(ItemListingAction.SyncWithBitwardenDismiss)
}
{ viewModel.trySendAction(ItemListingAction.SyncWithBitwardenDismiss) }
},
)
}
}
}
}
@Composable
private fun ItemListingDialogs(
@ -338,15 +333,9 @@ private fun ItemListingDialogs(
}
@Suppress("LongMethod")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ItemListingContent(
state: ItemListingState.ViewState.Content,
snackbarHostState: SnackbarHostState,
scrollBehavior: TopAppBarScrollBehavior,
onNavigateToSearch: () -> Unit,
onScanQrCodeClick: () -> Unit,
onEnterSetupKeyClick: () -> Unit,
onItemClick: (String) -> Unit,
onDropdownMenuClick: (VaultDropdownMenuAction, VerificationCodeDisplayItem) -> Unit,
onDownloadBitwardenClick: () -> Unit,
@ -355,62 +344,10 @@ private fun ItemListingContent(
onDismissSyncWithBitwardenClick: () -> Unit,
onSyncLearnMoreClick: () -> Unit,
onSectionExpandedClick: (SharedCodesDisplayState.SharedCodesAccountSection) -> Unit,
modifier: Modifier = Modifier,
) {
BitwardenScaffold(
modifier = Modifier
.fillMaxSize()
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
BitwardenMediumTopAppBar(
title = stringResource(id = BitwardenString.verification_codes),
scrollBehavior = scrollBehavior,
actions = {
BitwardenSearchActionItem(
contentDescription = stringResource(id = BitwardenString.search_codes),
onClick = onNavigateToSearch,
)
},
)
},
floatingActionButton = {
BitwardenExpandableFloatingActionButton(
modifier = Modifier.testTag("AddItemButton"),
items = persistentListOf(
ItemListingExpandableFabAction.ScanQrCode(
label = BitwardenString.scan_a_qr_code.asText(),
icon = IconData.Local(
iconRes = BitwardenDrawable.ic_camera_small,
contentDescription = BitwardenString.scan_a_qr_code.asText(),
testTag = "ScanQRCodeButton",
),
onScanQrCodeClick = onScanQrCodeClick,
),
ItemListingExpandableFabAction.EnterSetupKey(
label = BitwardenString.enter_key_manually.asText(),
icon = IconData.Local(
iconRes = BitwardenDrawable.ic_lock_encrypted_small,
contentDescription = BitwardenString.enter_key_manually.asText(),
testTag = "EnterSetupKeyButton",
),
onEnterSetupKeyClick = onEnterSetupKeyClick,
),
),
expandableFabIcon = ExpandableFabIcon(
icon = IconData.Local(
iconRes = BitwardenDrawable.ic_plus,
contentDescription = BitwardenString.add_item.asText(),
testTag = "AddItemButton",
),
iconRotation = 45f,
),
)
},
snackbarHost = { FirstTimeSyncSnackbarHost(state = snackbarHostState) },
) {
var isLocalHeaderExpanded by rememberSaveable { mutableStateOf(true) }
LazyColumn(
modifier = Modifier.fillMaxSize(),
) {
var isLocalHeaderExpanded by rememberSaveable { mutableStateOf(value = true) }
LazyColumn(modifier = modifier.fillMaxSize()) {
item(key = "action_card") {
ActionCard(
actionCardState = state.actionCard,
@ -474,15 +411,13 @@ private fun ItemListingContent(
),
isExpanded = isLocalHeaderExpanded,
onClick = { isLocalHeaderExpanded = !isLocalHeaderExpanded },
onClickLabel = if (isLocalHeaderExpanded) {
stringResource(
BitwardenString.local_items_are_expanded_click_to_collapse,
)
onClickLabel = stringResource(
id = if (isLocalHeaderExpanded) {
BitwardenString.local_items_are_expanded_click_to_collapse
} else {
stringResource(
BitwardenString.local_items_are_collapsed_click_to_expand,
)
BitwardenString.local_items_are_collapsed_click_to_expand
},
),
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin()
@ -529,13 +464,13 @@ private fun ItemListingContent(
onClick = {
onSectionExpandedClick(section)
},
onClickLabel = if (section.isExpanded) {
stringResource(BitwardenString.items_expanded_click_to_collapse)
onClickLabel = stringResource(
id = if (section.isExpanded) {
BitwardenString.items_expanded_click_to_collapse
} else {
stringResource(
BitwardenString.items_are_collapsed_click_to_expand,
)
BitwardenString.items_are_collapsed_click_to_expand
},
),
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin()
@ -595,74 +530,22 @@ private fun ItemListingContent(
}
}
}
}
/**
* Displays the item listing screen with no existing items.
*/
@Suppress("LongMethod")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EmptyItemListingContent(
modifier: Modifier = Modifier,
actionCardState: ItemListingState.ActionCardState,
appTheme: AppTheme,
scrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(
rememberTopAppBarState(),
),
onAddCodeClick: () -> Unit,
onScanQrCodeClick: () -> Unit,
onEnterSetupKeyClick: () -> Unit,
onDownloadBitwardenClick: () -> Unit,
onDismissDownloadBitwardenClick: () -> Unit,
onSyncWithBitwardenClick: () -> Unit,
onSyncLearnMoreClick: () -> Unit,
onDismissSyncWithBitwardenClick: () -> Unit,
) {
BitwardenScaffold(
modifier = Modifier
.fillMaxSize()
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
BitwardenTopAppBar(
title = stringResource(id = BitwardenString.verification_codes),
scrollBehavior = scrollBehavior,
navigationIcon = null,
)
},
floatingActionButton = {
BitwardenExpandableFloatingActionButton(
modifier = Modifier.testTag("AddItemButton"),
items = persistentListOf(
ItemListingExpandableFabAction.ScanQrCode(
label = BitwardenString.scan_a_qr_code.asText(),
icon = IconData.Local(
iconRes = BitwardenDrawable.ic_camera_small,
contentDescription = BitwardenString.scan_a_qr_code.asText(),
testTag = "ScanQRCodeButton",
),
onScanQrCodeClick = onScanQrCodeClick,
),
ItemListingExpandableFabAction.EnterSetupKey(
label = BitwardenString.enter_key_manually.asText(),
icon = IconData.Local(
iconRes = BitwardenDrawable.ic_lock_encrypted_small,
contentDescription = BitwardenString.enter_key_manually.asText(),
testTag = "EnterSetupKeyButton",
),
onEnterSetupKeyClick = onEnterSetupKeyClick,
),
),
expandableFabIcon = ExpandableFabIcon(
icon = IconData.Local(
iconRes = BitwardenDrawable.ic_plus,
contentDescription = BitwardenString.add_item.asText(),
testTag = "AddItemButton",
),
iconRotation = 45f,
),
)
},
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
@ -735,13 +618,12 @@ fun EmptyItemListingContent(
}
}
}
}
@Composable
private fun DownloadBitwardenActionCard(
modifier: Modifier = Modifier,
onDismissClick: () -> Unit,
onDownloadBitwardenClick: () -> Unit,
modifier: Modifier = Modifier,
) = BitwardenActionCard(
modifier = modifier,
cardSubtitle = stringResource(BitwardenString.download_bitwarden_card_message),
@ -761,10 +643,10 @@ private fun DownloadBitwardenActionCard(
@Suppress("LongMethod")
@Composable
private fun SyncWithBitwardenActionCard(
modifier: Modifier = Modifier,
onDismissClick: () -> Unit,
onAppSettingsClick: () -> Unit,
onLearnMoreClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Card(
modifier = modifier,
@ -865,7 +747,6 @@ private fun ActionCard(
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@Preview(showBackground = true)
private fun EmptyListingContentPreview() {
@ -873,8 +754,6 @@ private fun EmptyListingContentPreview() {
modifier = Modifier.padding(horizontal = 16.dp),
appTheme = AppTheme.DEFAULT,
onAddCodeClick = { },
onScanQrCodeClick = { },
onEnterSetupKeyClick = { },
actionCardState = ItemListingState.ActionCardState.DownloadBitwardenApp,
onDownloadBitwardenClick = { },
onDismissDownloadBitwardenClick = { },
@ -884,8 +763,6 @@ private fun EmptyListingContentPreview() {
)
}
@Suppress("LongMethod")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@Preview(showBackground = true)
private fun ContentPreview() {
@ -934,13 +811,6 @@ private fun ContentPreview() {
),
),
),
snackbarHostState = remember { SnackbarHostState() },
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(
rememberTopAppBarState(),
),
onNavigateToSearch = { },
onScanQrCodeClick = { },
onEnterSetupKeyClick = { },
onItemClick = { },
onDropdownMenuClick = { _, _ -> },
onDownloadBitwardenClick = { },