Skip to content

Commit 06b08d5

Browse files
Refactor usage of the ContentCard to always use the ContentBlock component. (#4357)
1 parent 4fb031d commit 06b08d5

File tree

6 files changed

+159
-216
lines changed

6 files changed

+159
-216
lines changed
Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,34 @@
11
package com.x8bit.bitwarden.ui.platform.components.card
22

33
import androidx.compose.foundation.background
4-
import androidx.compose.foundation.layout.Box
54
import androidx.compose.foundation.layout.Column
65
import androidx.compose.foundation.layout.fillMaxWidth
76
import androidx.compose.runtime.Composable
87
import androidx.compose.ui.Modifier
98
import androidx.compose.ui.draw.clip
10-
import androidx.compose.ui.unit.Dp
11-
import androidx.compose.ui.unit.dp
12-
import com.x8bit.bitwarden.ui.platform.base.util.bottomDivider
9+
import androidx.compose.ui.graphics.Color
10+
import androidx.compose.ui.text.TextStyle
11+
import com.x8bit.bitwarden.ui.platform.components.content.BitwardenContentBlock
12+
import com.x8bit.bitwarden.ui.platform.components.model.ContentBlockData
1313
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
1414
import kotlinx.collections.immutable.ImmutableList
1515

1616
/**
17-
* Reusable card for displaying content for a list of items with a generic type [T].
18-
* Items will be displayed in [Column] in the order they are provided with an optional divider
19-
* below them, besides the last item in the list.
17+
* Reusable card for displaying content block components in a vertical column with the card
18+
* shape. Content is drawn with a [BitwardenContentBlock].
2019
*
21-
* @param contentItems list of items to display.
22-
* @param content composable to render each item to the UI.
23-
* @param showBottomDivider whether to show a divider below each item.
24-
* @param bottomDividerPaddingStart padding to apply to the start of the divider.
25-
* @param bottomDividerPaddingEnd padding to apply to the end of the divider.
20+
* @param contentItems list of [ContentBlockData] items to display.
21+
* @param contentHeaderTextStyle the text style to use for the header text of the content.
22+
* @param contentSubtitleTextStyle the text style to use for the subtitle text of the content.
23+
* @param contentBackgroundColor the background color to use for the content.
2624
*/
2725
@Composable
28-
fun <T> BitwardenContentCard(
29-
contentItems: ImmutableList<T>,
26+
fun BitwardenContentCard(
27+
contentItems: ImmutableList<ContentBlockData>,
3028
modifier: Modifier = Modifier,
31-
showBottomDivider: Boolean = true,
32-
bottomDividerPaddingStart: Dp = 0.dp,
33-
bottomDividerPaddingEnd: Dp = 0.dp,
34-
content: @Composable (T) -> Unit,
29+
contentHeaderTextStyle: TextStyle = BitwardenTheme.typography.titleSmall,
30+
contentSubtitleTextStyle: TextStyle = BitwardenTheme.typography.bodyMedium,
31+
contentBackgroundColor: Color = BitwardenTheme.colorScheme.background.secondary,
3532
) {
3633
Column(
3734
modifier = modifier
@@ -40,17 +37,13 @@ fun <T> BitwardenContentCard(
4037
.background(color = BitwardenTheme.colorScheme.background.secondary),
4138
) {
4239
contentItems.forEachIndexed { index, item ->
43-
Box(
44-
modifier = Modifier
45-
.fillMaxWidth()
46-
.bottomDivider(
47-
enabled = index != contentItems.lastIndex && showBottomDivider,
48-
paddingStart = bottomDividerPaddingStart,
49-
paddingEnd = bottomDividerPaddingEnd,
50-
),
51-
) {
52-
content(item)
53-
}
40+
BitwardenContentBlock(
41+
data = item,
42+
showDivider = index != contentItems.lastIndex,
43+
headerTextStyle = contentHeaderTextStyle,
44+
subtitleTextStyle = contentSubtitleTextStyle,
45+
backgroundColor = contentBackgroundColor,
46+
)
5447
}
5548
}
5649
}

app/src/main/java/com/x8bit/bitwarden/ui/platform/components/content/BitwardenContentBlock.kt

Lines changed: 76 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,21 @@ import androidx.compose.foundation.layout.width
1212
import androidx.compose.material3.Icon
1313
import androidx.compose.material3.Text
1414
import androidx.compose.runtime.Composable
15+
import androidx.compose.runtime.getValue
16+
import androidx.compose.runtime.mutableStateOf
17+
import androidx.compose.runtime.remember
18+
import androidx.compose.runtime.setValue
1519
import androidx.compose.ui.Alignment
1620
import androidx.compose.ui.Modifier
1721
import androidx.compose.ui.graphics.Color
22+
import androidx.compose.ui.layout.onGloballyPositioned
23+
import androidx.compose.ui.platform.LocalDensity
1824
import androidx.compose.ui.text.AnnotatedString
1925
import androidx.compose.ui.text.TextStyle
2026
import androidx.compose.ui.tooling.preview.Preview
2127
import androidx.compose.ui.unit.dp
28+
import com.x8bit.bitwarden.R
29+
import com.x8bit.bitwarden.ui.platform.base.util.bottomDivider
2230
import com.x8bit.bitwarden.ui.platform.components.model.ContentBlockData
2331
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
2432
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
@@ -34,6 +42,7 @@ fun BitwardenContentBlock(
3442
headerTextStyle: TextStyle = BitwardenTheme.typography.titleSmall,
3543
subtitleTextStyle: TextStyle = BitwardenTheme.typography.bodyMedium,
3644
backgroundColor: Color = BitwardenTheme.colorScheme.background.secondary,
45+
showDivider: Boolean = true,
3746
) {
3847
BitwardenContentBlock(
3948
headerText = data.headerText,
@@ -43,6 +52,7 @@ fun BitwardenContentBlock(
4352
subtitleTextStyle = subtitleTextStyle,
4453
iconVectorResource = data.iconVectorResource,
4554
backgroundColor = backgroundColor,
55+
showDivider = showDivider,
4656
)
4757
}
4858

@@ -55,29 +65,47 @@ private fun BitwardenContentBlock(
5565
headerText: AnnotatedString,
5666
modifier: Modifier = Modifier,
5767
headerTextStyle: TextStyle = BitwardenTheme.typography.titleSmall,
58-
subtitleText: String? = null,
68+
subtitleText: AnnotatedString? = null,
5969
subtitleTextStyle: TextStyle = BitwardenTheme.typography.bodyMedium,
70+
showDivider: Boolean = true,
6071
@DrawableRes iconVectorResource: Int? = null,
6172
backgroundColor: Color = BitwardenTheme.colorScheme.background.secondary,
6273
) {
74+
var dividerStartPadding by remember { mutableStateOf(0.dp) }
75+
val localDensity = LocalDensity.current
76+
6377
Row(
64-
modifier = modifier
78+
modifier = Modifier
6579
.fillMaxWidth()
66-
.background(backgroundColor),
80+
.background(backgroundColor)
81+
.bottomDivider(
82+
enabled = showDivider,
83+
paddingStart = dividerStartPadding,
84+
)
85+
.then(modifier),
6786
verticalAlignment = Alignment.CenterVertically,
6887
) {
69-
iconVectorResource
70-
?.let {
71-
Spacer(Modifier.width(12.dp))
72-
Icon(
73-
painter = rememberVectorPainter(it),
74-
contentDescription = null,
75-
tint = BitwardenTheme.colorScheme.icon.secondary,
76-
modifier = Modifier.size(24.dp),
77-
)
78-
Spacer(Modifier.width(12.dp))
79-
}
80-
?: Spacer(Modifier.width(16.dp))
88+
Row(
89+
modifier = Modifier
90+
.onGloballyPositioned {
91+
dividerStartPadding = with(localDensity) {
92+
it.size.width.toDp()
93+
}
94+
},
95+
) {
96+
iconVectorResource
97+
?.let {
98+
Spacer(Modifier.width(12.dp))
99+
Icon(
100+
painter = rememberVectorPainter(it),
101+
contentDescription = null,
102+
tint = BitwardenTheme.colorScheme.icon.secondary,
103+
modifier = Modifier.size(24.dp),
104+
)
105+
Spacer(Modifier.width(12.dp))
106+
}
107+
?: Spacer(Modifier.width(16.dp))
108+
}
81109

82110
Column {
83111
Spacer(Modifier.height(12.dp))
@@ -103,12 +131,38 @@ private fun BitwardenContentBlock(
103131
@Composable
104132
private fun BitwardenContentBlock_preview() {
105133
BitwardenTheme {
106-
BitwardenContentBlock(
107-
data = ContentBlockData(
108-
headerText = "Header",
109-
subtitleText = "Subtitle",
110-
iconVectorResource = null,
111-
),
112-
)
134+
Column(
135+
modifier = Modifier.background(color = BitwardenTheme.colorScheme.background.primary),
136+
) {
137+
BitwardenContentBlock(
138+
data = ContentBlockData(
139+
headerText = "Header",
140+
subtitleText = "Subtitle",
141+
iconVectorResource = null,
142+
),
143+
)
144+
BitwardenContentBlock(
145+
data = ContentBlockData(
146+
headerText = "Header",
147+
subtitleText = "Subtitle",
148+
iconVectorResource = R.drawable.ic_number2,
149+
),
150+
)
151+
BitwardenContentBlock(
152+
data = ContentBlockData(
153+
headerText = "Header",
154+
subtitleText = "Subtitle",
155+
iconVectorResource = null,
156+
),
157+
showDivider = false,
158+
)
159+
BitwardenContentBlock(
160+
data = ContentBlockData(
161+
headerText = "Header",
162+
subtitleText = "Subtitle",
163+
iconVectorResource = null,
164+
),
165+
)
166+
}
113167
}
114168
}

app/src/main/java/com/x8bit/bitwarden/ui/platform/components/model/ContentBlockData.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.platform.components.model
33
import androidx.annotation.DrawableRes
44
import androidx.compose.runtime.Immutable
55
import androidx.compose.ui.text.AnnotatedString
6+
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
67
import com.x8bit.bitwarden.ui.platform.components.content.BitwardenContentBlock
78

89
/**
@@ -12,7 +13,7 @@ import com.x8bit.bitwarden.ui.platform.components.content.BitwardenContentBlock
1213
@Immutable
1314
data class ContentBlockData(
1415
val headerText: AnnotatedString,
15-
val subtitleText: String? = null,
16+
val subtitleText: AnnotatedString? = null,
1617
@DrawableRes val iconVectorResource: Int? = null,
1718
) {
1819
/**
@@ -24,8 +25,8 @@ data class ContentBlockData(
2425
subtitleText: String? = null,
2526
@DrawableRes iconVectorResource: Int? = null,
2627
) : this(
27-
headerText = AnnotatedString(headerText),
28-
subtitleText = subtitleText,
28+
headerText = headerText.toAnnotatedString(),
29+
subtitleText = subtitleText?.toAnnotatedString(),
2930
iconVectorResource = iconVectorResource,
3031
)
3132
}

app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/importlogins/ImportLoginsScreen.kt

Lines changed: 40 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
4343
import com.x8bit.bitwarden.ui.platform.base.util.bitwardenBoldSpanStyle
4444
import com.x8bit.bitwarden.ui.platform.base.util.createAnnotatedString
4545
import com.x8bit.bitwarden.ui.platform.base.util.standardHorizontalMargin
46+
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
4647
import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
4748
import com.x8bit.bitwarden.ui.platform.components.appbar.NavigationIcon
4849
import com.x8bit.bitwarden.ui.platform.components.bottomsheet.BitwardenModalBottomSheet
4950
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenFilledButton
5051
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenOutlinedButton
5152
import com.x8bit.bitwarden.ui.platform.components.card.BitwardenContentCard
52-
import com.x8bit.bitwarden.ui.platform.components.content.BitwardenContentBlock
5353
import com.x8bit.bitwarden.ui.platform.components.content.BitwardenFullScreenLoadingContent
5454
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
5555
import com.x8bit.bitwarden.ui.platform.components.model.ContentBlockData
@@ -62,7 +62,6 @@ import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
6262
import com.x8bit.bitwarden.ui.vault.feature.importlogins.components.ImportLoginsInstructionStep
6363
import com.x8bit.bitwarden.ui.vault.feature.importlogins.handlers.ImportLoginHandler
6464
import com.x8bit.bitwarden.ui.vault.feature.importlogins.handlers.rememberImportLoginHandler
65-
import com.x8bit.bitwarden.ui.vault.feature.importlogins.model.InstructionStep
6665
import kotlinx.collections.immutable.persistentListOf
6766

6867
private const val IMPORT_HELP_URL = "https://bitwarden.com/help/import-data/"
@@ -315,20 +314,21 @@ private fun ImportLoginsStepOneContent(
315314
stepText = stringResource(R.string.step_1_of_3),
316315
stepTitle = stringResource(R.string.export_your_saved_logins),
317316
instructions = persistentListOf(
318-
InstructionStep(
319-
stepNumber = 1,
320-
instructionText = instruction1,
321-
additionalText = null,
317+
ContentBlockData(
318+
iconVectorResource = R.drawable.ic_number1,
319+
headerText = instruction1,
320+
subtitleText = null,
322321
),
323-
InstructionStep(
324-
stepNumber = 2,
325-
instructionText = instruction2,
326-
additionalText = null,
322+
ContentBlockData(
323+
iconVectorResource = R.drawable.ic_number2,
324+
headerText = instruction2,
325+
subtitleText = null,
327326
),
328-
InstructionStep(
329-
stepNumber = 3,
330-
instructionText = instruction3,
331-
additionalText = stringResource(R.string.delete_this_file_after_import_is_complete),
327+
ContentBlockData(
328+
iconVectorResource = R.drawable.ic_number3,
329+
headerText = instruction3,
330+
subtitleText = stringResource(R.string.delete_this_file_after_import_is_complete)
331+
.toAnnotatedString(),
332332
),
333333
),
334334
onBackClick = onBackClick,
@@ -369,15 +369,15 @@ private fun ImportLoginsStepTwoContent(
369369
stepText = stringResource(R.string.step_2_of_3),
370370
stepTitle = stringResource(R.string.log_in_to_bitwarden),
371371
instructions = persistentListOf(
372-
InstructionStep(
373-
stepNumber = 1,
374-
instructionText = instruction1,
375-
additionalText = null,
372+
ContentBlockData(
373+
iconVectorResource = R.drawable.ic_number1,
374+
headerText = instruction1,
375+
subtitleText = null,
376376
),
377-
InstructionStep(
378-
stepNumber = 2,
379-
instructionText = instruction2,
380-
additionalText = null,
377+
ContentBlockData(
378+
iconVectorResource = R.drawable.ic_number2,
379+
headerText = instruction2,
380+
subtitleText = null,
381381
),
382382
),
383383
onBackClick = onBackClick,
@@ -435,25 +435,25 @@ private fun ImportLoginsStepThreeContent(
435435
stepText = stringResource(R.string.step_3_of_3),
436436
stepTitle = stringResource(R.string.import_logins_to_bitwarden),
437437
instructions = persistentListOf(
438-
InstructionStep(
439-
stepNumber = 1,
440-
instructionText = instruction1,
441-
additionalText = null,
438+
ContentBlockData(
439+
iconVectorResource = R.drawable.ic_number1,
440+
headerText = instruction1,
441+
subtitleText = null,
442442
),
443-
InstructionStep(
444-
stepNumber = 2,
445-
instructionText = instruction2,
446-
additionalText = null,
443+
ContentBlockData(
444+
iconVectorResource = R.drawable.ic_number2,
445+
headerText = instruction2,
446+
subtitleText = null,
447447
),
448-
InstructionStep(
449-
stepNumber = 3,
450-
instructionText = instruction3,
451-
additionalText = null,
448+
ContentBlockData(
449+
iconVectorResource = R.drawable.ic_number3,
450+
headerText = instruction3,
451+
subtitleText = null,
452452
),
453-
InstructionStep(
454-
stepNumber = 4,
455-
instructionText = instruction4,
456-
additionalText = null,
453+
ContentBlockData(
454+
iconVectorResource = R.drawable.ic_number4,
455+
headerText = instruction4,
456+
subtitleText = null,
457457
),
458458
),
459459
onBackClick = onBackClick,
@@ -524,15 +524,9 @@ private fun ImportLoginsSuccessBottomSheetContent(
524524
iconVectorResource = R.drawable.ic_shield,
525525
),
526526
),
527-
bottomDividerPaddingStart = 48.dp,
528-
showBottomDivider = true,
529527
modifier = Modifier.standardHorizontalMargin(),
530-
) { contentData ->
531-
BitwardenContentBlock(
532-
data = contentData,
533-
subtitleTextStyle = BitwardenTheme.typography.bodySmall,
534-
)
535-
}
528+
contentSubtitleTextStyle = BitwardenTheme.typography.bodySmall,
529+
)
536530
Spacer(Modifier.height(24.dp))
537531
BitwardenFilledButton(
538532
label = stringResource(R.string.got_it),

0 commit comments

Comments
 (0)