Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor usage of the ContentCard to always use the ContentBlock component. #4357

Merged
merged 3 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,37 +1,34 @@
package com.x8bit.bitwarden.ui.platform.components.card

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.x8bit.bitwarden.ui.platform.base.util.bottomDivider
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import com.x8bit.bitwarden.ui.platform.components.content.BitwardenContentBlock
import com.x8bit.bitwarden.ui.platform.components.model.ContentBlockData
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
import kotlinx.collections.immutable.ImmutableList

/**
* Reusable card for displaying content for a list of items with a generic type [T].
* Items will be displayed in [Column] in the order they are provided with an optional divider
* below them, besides the last item in the list.
* Reusable card for displaying content block components in a vertical column with the card
* shape. Content is drawn with a [BitwardenContentBlock].
*
* @param contentItems list of items to display.
* @param content composable to render each item to the UI.
* @param showBottomDivider whether to show a divider below each item.
* @param bottomDividerPaddingStart padding to apply to the start of the divider.
* @param bottomDividerPaddingEnd padding to apply to the end of the divider.
* @param contentItems list of [ContentBlockData] items to display.
* @param contentHeaderTextStyle the text style to use for the header text of the content.
* @param contentSubtitleTextStyle the text style to use for the subtitle text of the content.
* @param contentBackgroundColor the background color to use for the content.
*/
@Composable
fun <T> BitwardenContentCard(
contentItems: ImmutableList<T>,
fun BitwardenContentCard(
contentItems: ImmutableList<ContentBlockData>,
modifier: Modifier = Modifier,
showBottomDivider: Boolean = true,
bottomDividerPaddingStart: Dp = 0.dp,
bottomDividerPaddingEnd: Dp = 0.dp,
content: @Composable (T) -> Unit,
contentHeaderTextStyle: TextStyle = BitwardenTheme.typography.titleSmall,
contentSubtitleTextStyle: TextStyle = BitwardenTheme.typography.bodyMedium,
contentBackgroundColor: Color = BitwardenTheme.colorScheme.background.secondary,
) {
Column(
modifier = modifier
Expand All @@ -40,17 +37,13 @@ fun <T> BitwardenContentCard(
.background(color = BitwardenTheme.colorScheme.background.secondary),
) {
contentItems.forEachIndexed { index, item ->
Box(
modifier = Modifier
.fillMaxWidth()
.bottomDivider(
enabled = index != contentItems.lastIndex && showBottomDivider,
paddingStart = bottomDividerPaddingStart,
paddingEnd = bottomDividerPaddingEnd,
),
) {
content(item)
}
BitwardenContentBlock(
data = item,
showDivider = index != contentItems.lastIndex,
headerTextStyle = contentHeaderTextStyle,
subtitleTextStyle = contentSubtitleTextStyle,
backgroundColor = contentBackgroundColor,
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,21 @@ import androidx.compose.foundation.layout.width
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.ui.platform.base.util.bottomDivider
import com.x8bit.bitwarden.ui.platform.components.model.ContentBlockData
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
Expand All @@ -34,6 +42,7 @@ fun BitwardenContentBlock(
headerTextStyle: TextStyle = BitwardenTheme.typography.titleSmall,
subtitleTextStyle: TextStyle = BitwardenTheme.typography.bodyMedium,
backgroundColor: Color = BitwardenTheme.colorScheme.background.secondary,
showDivider: Boolean = true,
) {
BitwardenContentBlock(
headerText = data.headerText,
Expand All @@ -43,6 +52,7 @@ fun BitwardenContentBlock(
subtitleTextStyle = subtitleTextStyle,
iconVectorResource = data.iconVectorResource,
backgroundColor = backgroundColor,
showDivider = showDivider,
)
}

Expand All @@ -55,29 +65,46 @@ private fun BitwardenContentBlock(
headerText: AnnotatedString,
modifier: Modifier = Modifier,
headerTextStyle: TextStyle = BitwardenTheme.typography.titleSmall,
subtitleText: String? = null,
subtitleText: AnnotatedString? = null,
subtitleTextStyle: TextStyle = BitwardenTheme.typography.bodyMedium,
showDivider: Boolean = true,
@DrawableRes iconVectorResource: Int? = null,
backgroundColor: Color = BitwardenTheme.colorScheme.background.secondary,
) {
var dividerStartPadding by remember { mutableStateOf(0.dp) }
val localDensity = LocalDensity.current

Row(
modifier = modifier
.fillMaxWidth()
.background(backgroundColor),
.background(backgroundColor)
.bottomDivider(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have an scenarios where the incoming modifier will have a padding applied?

If so we might want to do something like this:

       modifier = Modifier
            .fillMaxWidth()
            .background(backgroundColor)
            .bottomDivider(
                enabled = showDivider,
                paddingStart = dividerStartPadding,
            )
            .then(modifier),

That will enforce that the background and divider is applied before any padding on the modifier.

enabled = showDivider,
paddingStart = dividerStartPadding,
),
verticalAlignment = Alignment.CenterVertically,
) {
iconVectorResource
?.let {
Spacer(Modifier.width(12.dp))
Icon(
painter = rememberVectorPainter(it),
contentDescription = null,
tint = BitwardenTheme.colorScheme.icon.secondary,
modifier = Modifier.size(24.dp),
)
Spacer(Modifier.width(12.dp))
}
?: Spacer(Modifier.width(16.dp))
Row(
modifier = Modifier
.onGloballyPositioned {
dividerStartPadding = with(localDensity) {
it.size.width.toDp()
}
},
) {
iconVectorResource
?.let {
Spacer(Modifier.width(12.dp))
Icon(
painter = rememberVectorPainter(it),
contentDescription = null,
tint = BitwardenTheme.colorScheme.icon.secondary,
modifier = Modifier.size(24.dp),
)
Spacer(Modifier.width(12.dp))
}
?: Spacer(Modifier.width(16.dp))
}

Column {
Spacer(Modifier.height(12.dp))
Expand All @@ -103,12 +130,38 @@ private fun BitwardenContentBlock(
@Composable
private fun BitwardenContentBlock_preview() {
BitwardenTheme {
BitwardenContentBlock(
data = ContentBlockData(
headerText = "Header",
subtitleText = "Subtitle",
iconVectorResource = null,
),
)
Column(
modifier = Modifier.background(color = BitwardenTheme.colorScheme.background.primary),
) {
BitwardenContentBlock(
data = ContentBlockData(
headerText = "Header",
subtitleText = "Subtitle",
iconVectorResource = null,
),
)
BitwardenContentBlock(
data = ContentBlockData(
headerText = "Header",
subtitleText = "Subtitle",
iconVectorResource = R.drawable.ic_number2,
),
)
BitwardenContentBlock(
data = ContentBlockData(
headerText = "Header",
subtitleText = "Subtitle",
iconVectorResource = null,
),
showDivider = false,
)
BitwardenContentBlock(
data = ContentBlockData(
headerText = "Header",
subtitleText = "Subtitle",
iconVectorResource = null,
),
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.platform.components.model
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Immutable
import androidx.compose.ui.text.AnnotatedString
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
import com.x8bit.bitwarden.ui.platform.components.content.BitwardenContentBlock

/**
Expand All @@ -12,7 +13,7 @@ import com.x8bit.bitwarden.ui.platform.components.content.BitwardenContentBlock
@Immutable
data class ContentBlockData(
val headerText: AnnotatedString,
val subtitleText: String? = null,
val subtitleText: AnnotatedString? = null,
@DrawableRes val iconVectorResource: Int? = null,
) {
/**
Expand All @@ -24,8 +25,8 @@ data class ContentBlockData(
subtitleText: String? = null,
@DrawableRes iconVectorResource: Int? = null,
) : this(
headerText = AnnotatedString(headerText),
subtitleText = subtitleText,
headerText = headerText.toAnnotatedString(),
subtitleText = subtitleText?.toAnnotatedString(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿ‘

iconVectorResource = iconVectorResource,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
import com.x8bit.bitwarden.ui.platform.base.util.bitwardenBoldSpanStyle
import com.x8bit.bitwarden.ui.platform.base.util.createAnnotatedString
import com.x8bit.bitwarden.ui.platform.base.util.standardHorizontalMargin
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
import com.x8bit.bitwarden.ui.platform.components.appbar.NavigationIcon
import com.x8bit.bitwarden.ui.platform.components.bottomsheet.BitwardenModalBottomSheet
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenFilledButton
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenOutlinedButton
import com.x8bit.bitwarden.ui.platform.components.card.BitwardenContentCard
import com.x8bit.bitwarden.ui.platform.components.content.BitwardenContentBlock
import com.x8bit.bitwarden.ui.platform.components.content.BitwardenFullScreenLoadingContent
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
import com.x8bit.bitwarden.ui.platform.components.model.ContentBlockData
Expand All @@ -62,7 +62,6 @@ import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
import com.x8bit.bitwarden.ui.vault.feature.importlogins.components.ImportLoginsInstructionStep
import com.x8bit.bitwarden.ui.vault.feature.importlogins.handlers.ImportLoginHandler
import com.x8bit.bitwarden.ui.vault.feature.importlogins.handlers.rememberImportLoginHandler
import com.x8bit.bitwarden.ui.vault.feature.importlogins.model.InstructionStep
import kotlinx.collections.immutable.persistentListOf

private const val IMPORT_HELP_URL = "https://bitwarden.com/help/import-data/"
Expand Down Expand Up @@ -315,20 +314,21 @@ private fun ImportLoginsStepOneContent(
stepText = stringResource(R.string.step_1_of_3),
stepTitle = stringResource(R.string.export_your_saved_logins),
instructions = persistentListOf(
InstructionStep(
stepNumber = 1,
instructionText = instruction1,
additionalText = null,
ContentBlockData(
iconVectorResource = R.drawable.ic_number1,
headerText = instruction1,
subtitleText = null,
),
InstructionStep(
stepNumber = 2,
instructionText = instruction2,
additionalText = null,
ContentBlockData(
iconVectorResource = R.drawable.ic_number2,
headerText = instruction2,
subtitleText = null,
),
InstructionStep(
stepNumber = 3,
instructionText = instruction3,
additionalText = stringResource(R.string.delete_this_file_after_import_is_complete),
ContentBlockData(
iconVectorResource = R.drawable.ic_number3,
headerText = instruction3,
subtitleText = stringResource(R.string.delete_this_file_after_import_is_complete)
.toAnnotatedString(),
),
),
onBackClick = onBackClick,
Expand Down Expand Up @@ -369,15 +369,15 @@ private fun ImportLoginsStepTwoContent(
stepText = stringResource(R.string.step_2_of_3),
stepTitle = stringResource(R.string.log_in_to_bitwarden),
instructions = persistentListOf(
InstructionStep(
stepNumber = 1,
instructionText = instruction1,
additionalText = null,
ContentBlockData(
iconVectorResource = R.drawable.ic_number1,
headerText = instruction1,
subtitleText = null,
),
InstructionStep(
stepNumber = 2,
instructionText = instruction2,
additionalText = null,
ContentBlockData(
iconVectorResource = R.drawable.ic_number2,
headerText = instruction2,
subtitleText = null,
),
),
onBackClick = onBackClick,
Expand Down Expand Up @@ -435,25 +435,25 @@ private fun ImportLoginsStepThreeContent(
stepText = stringResource(R.string.step_3_of_3),
stepTitle = stringResource(R.string.import_logins_to_bitwarden),
instructions = persistentListOf(
InstructionStep(
stepNumber = 1,
instructionText = instruction1,
additionalText = null,
ContentBlockData(
iconVectorResource = R.drawable.ic_number1,
headerText = instruction1,
subtitleText = null,
),
InstructionStep(
stepNumber = 2,
instructionText = instruction2,
additionalText = null,
ContentBlockData(
iconVectorResource = R.drawable.ic_number2,
headerText = instruction2,
subtitleText = null,
),
InstructionStep(
stepNumber = 3,
instructionText = instruction3,
additionalText = null,
ContentBlockData(
iconVectorResource = R.drawable.ic_number3,
headerText = instruction3,
subtitleText = null,
),
InstructionStep(
stepNumber = 4,
instructionText = instruction4,
additionalText = null,
ContentBlockData(
iconVectorResource = R.drawable.ic_number4,
headerText = instruction4,
subtitleText = null,
),
),
onBackClick = onBackClick,
Expand Down Expand Up @@ -524,15 +524,9 @@ private fun ImportLoginsSuccessBottomSheetContent(
iconVectorResource = R.drawable.ic_shield,
),
),
bottomDividerPaddingStart = 48.dp,
showBottomDivider = true,
modifier = Modifier.standardHorizontalMargin(),
) { contentData ->
BitwardenContentBlock(
data = contentData,
subtitleTextStyle = BitwardenTheme.typography.bodySmall,
)
}
contentSubtitleTextStyle = BitwardenTheme.typography.bodySmall,
)
Spacer(Modifier.height(24.dp))
BitwardenFilledButton(
label = stringResource(R.string.got_it),
Expand Down
Loading