Skip to content

Commit 7f64b28

Browse files
Merge pull request thunderbird#9524 from rafaeltonholo/feat/9312/add-outlined-card-and-cards-default
feat(design-system): add outlined card and card defaults object
2 parents bc29015 + 25c8376 commit 7f64b28

10 files changed

Lines changed: 539 additions & 17 deletions

File tree

app-ui-catalog/src/main/kotlin/net/thunderbird/ui/catalog/ui/page/atom/CatalogAtomContent.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ import androidx.compose.ui.Modifier
55
import kotlinx.collections.immutable.ImmutableList
66
import net.thunderbird.ui.catalog.ui.page.CatalogPageContract
77
import net.thunderbird.ui.catalog.ui.page.atom.CatalogAtomPage.BUTTON
8+
import net.thunderbird.ui.catalog.ui.page.atom.CatalogAtomPage.CARD
89
import net.thunderbird.ui.catalog.ui.page.atom.CatalogAtomPage.COLOR
910
import net.thunderbird.ui.catalog.ui.page.atom.CatalogAtomPage.ICON
1011
import net.thunderbird.ui.catalog.ui.page.atom.CatalogAtomPage.IMAGE
1112
import net.thunderbird.ui.catalog.ui.page.atom.CatalogAtomPage.SELECTION_CONTROL
1213
import net.thunderbird.ui.catalog.ui.page.atom.CatalogAtomPage.TEXT_FIELD
1314
import net.thunderbird.ui.catalog.ui.page.atom.CatalogAtomPage.TYPOGRAPHY
1415
import net.thunderbird.ui.catalog.ui.page.atom.items.buttonItems
16+
import net.thunderbird.ui.catalog.ui.page.atom.items.cardItems
1517
import net.thunderbird.ui.catalog.ui.page.atom.items.colorItems
1618
import net.thunderbird.ui.catalog.ui.page.atom.items.iconItems
1719
import net.thunderbird.ui.catalog.ui.page.atom.items.imageItems
@@ -40,6 +42,7 @@ fun CatalogAtomContent(
4042
TEXT_FIELD -> textFieldItems()
4143
ICON -> iconItems()
4244
IMAGE -> imageItems()
45+
CARD -> cardItems()
4346
}
4447
},
4548
onRenderFullScreenPage = {},

app-ui-catalog/src/main/kotlin/net/thunderbird/ui/catalog/ui/page/atom/CatalogAtomPage.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ enum class CatalogAtomPage(
1414
TEXT_FIELD("TextFields"),
1515
ICON("Icons"),
1616
IMAGE("Images"),
17+
CARD("Cards"),
1718
;
1819

1920
override fun toString(): String {
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package net.thunderbird.ui.catalog.ui.page.atom.items
2+
3+
import androidx.compose.foundation.layout.Box
4+
import androidx.compose.foundation.layout.padding
5+
import androidx.compose.foundation.lazy.grid.LazyGridScope
6+
import androidx.compose.ui.Modifier
7+
import app.k9mail.core.ui.compose.designsystem.atom.card.CardElevated
8+
import app.k9mail.core.ui.compose.designsystem.atom.card.CardFilled
9+
import app.k9mail.core.ui.compose.designsystem.atom.card.CardOutlined
10+
import app.k9mail.core.ui.compose.designsystem.atom.text.TextBodyLarge
11+
import app.k9mail.core.ui.compose.theme2.MainTheme
12+
import net.thunderbird.ui.catalog.ui.page.common.list.sectionHeaderItem
13+
import net.thunderbird.ui.catalog.ui.page.common.list.wideItem
14+
15+
fun LazyGridScope.cardItems() {
16+
sectionCardElevated()
17+
sectionCardFilled()
18+
sectionCardOutlined()
19+
}
20+
21+
fun LazyGridScope.sectionCardElevated() {
22+
sectionHeaderItem(text = "Card - Elevated")
23+
wideItem {
24+
CardElevated(
25+
modifier = Modifier.padding(horizontal = MainTheme.spacings.triple),
26+
) {
27+
Box(
28+
modifier = Modifier.padding(MainTheme.spacings.triple),
29+
) {
30+
TextBodyLarge(text = "Inside a CardElevated")
31+
}
32+
}
33+
}
34+
}
35+
36+
fun LazyGridScope.sectionCardFilled() {
37+
sectionHeaderItem(text = "Card - Filled")
38+
wideItem {
39+
CardFilled(
40+
modifier = Modifier.padding(horizontal = MainTheme.spacings.triple),
41+
) {
42+
Box(
43+
modifier = Modifier.padding(MainTheme.spacings.triple),
44+
) {
45+
TextBodyLarge(text = "Inside a CardFilled")
46+
}
47+
}
48+
}
49+
}
50+
51+
fun LazyGridScope.sectionCardOutlined() {
52+
sectionHeaderItem(text = "Card - Outlined")
53+
wideItem {
54+
CardOutlined(
55+
modifier = Modifier.padding(horizontal = MainTheme.spacings.triple),
56+
) {
57+
Box(
58+
modifier = Modifier.padding(MainTheme.spacings.triple),
59+
) {
60+
TextBodyLarge(text = "Inside a CardOutlined")
61+
}
62+
}
63+
}
64+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package app.k9mail.core.ui.compose.designsystem.atom.card
2+
3+
import androidx.compose.foundation.layout.Box
4+
import androidx.compose.foundation.layout.padding
5+
import androidx.compose.runtime.Composable
6+
import androidx.compose.ui.Modifier
7+
import androidx.compose.ui.tooling.preview.PreviewLightDark
8+
import app.k9mail.core.ui.compose.designsystem.PreviewWithThemesLightDark
9+
import app.k9mail.core.ui.compose.designsystem.atom.Surface
10+
import app.k9mail.core.ui.compose.designsystem.atom.text.TextBodyMedium
11+
import app.k9mail.core.ui.compose.theme2.MainTheme
12+
13+
@PreviewLightDark
14+
@Composable
15+
private fun CardOutlinedPreview() {
16+
PreviewWithThemesLightDark {
17+
Surface(modifier = Modifier.padding(MainTheme.spacings.quadruple)) {
18+
CardOutlined {
19+
Box(modifier = Modifier.padding(MainTheme.spacings.double)) {
20+
TextBodyMedium("Text in card")
21+
}
22+
}
23+
}
24+
}
25+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package app.k9mail.core.ui.compose.designsystem.atom.card
2+
3+
import androidx.compose.ui.graphics.Color
4+
import androidx.compose.material3.CardColors as Material3CardColors
5+
6+
/**
7+
* Represents the colors used by a card.
8+
*
9+
* See [CardDefaults.cardColors], [CardDefaults.outlinedCardColors], and [CardDefaults.elevatedCardColors].
10+
*
11+
* @property containerColor The color used for the background of this card.
12+
* @property contentColor The preferred color for content inside this card.
13+
* @property disabledContainerColor The color used for the background of this card when it is not enabled.
14+
* @property disabledContentColor The preferred color for content inside this card when it is not enabled.
15+
*/
16+
data class CardColors(
17+
val containerColor: Color,
18+
val contentColor: Color,
19+
val disabledContainerColor: Color,
20+
val disabledContentColor: Color,
21+
)
22+
23+
/**
24+
* Converts a [Material3CardColors] to a [CardColors].
25+
*/
26+
internal fun Material3CardColors.toCardColors(): CardColors =
27+
CardColors(
28+
containerColor = containerColor,
29+
contentColor = contentColor,
30+
disabledContainerColor = disabledContainerColor,
31+
disabledContentColor = disabledContentColor,
32+
)
33+
34+
/**
35+
* Converts a [CardColors] to a Material 3 [Material3CardColors].
36+
*/
37+
internal fun CardColors.toMaterial3CardColors(): Material3CardColors =
38+
Material3CardColors(
39+
containerColor = containerColor,
40+
contentColor = contentColor,
41+
disabledContainerColor = disabledContainerColor,
42+
disabledContentColor = disabledContentColor,
43+
)
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
package app.k9mail.core.ui.compose.designsystem.atom.card
2+
3+
import androidx.compose.foundation.BorderStroke
4+
import androidx.compose.foundation.interaction.Interaction
5+
import androidx.compose.material3.Card
6+
import androidx.compose.material3.ElevatedCard
7+
import androidx.compose.material3.OutlinedCard
8+
import androidx.compose.material3.contentColorFor
9+
import androidx.compose.runtime.Composable
10+
import androidx.compose.ui.graphics.Color
11+
import androidx.compose.ui.graphics.Shape
12+
import androidx.compose.ui.unit.Dp
13+
import app.k9mail.core.ui.compose.theme2.MainTheme
14+
import androidx.compose.material3.CardDefaults as Material3CardDefaults
15+
16+
/**
17+
* Contains the default values used by all card types.
18+
*/
19+
object CardDefaults {
20+
// shape Defaults
21+
/** Default shape for a card. */
22+
val shape: Shape
23+
@Composable get() = Material3CardDefaults.shape
24+
25+
/** Default shape for an elevated card. */
26+
val elevatedShape: Shape
27+
@Composable get() = Material3CardDefaults.elevatedShape
28+
29+
/** Default shape for an outlined card. */
30+
val outlinedShape: Shape
31+
@Composable get() = Material3CardDefaults.outlinedShape
32+
33+
internal const val DISABLED_ALPHA = 0.38f
34+
35+
/**
36+
* Creates a [CardElevation] that will animate between the provided values according to the
37+
* Material specification for a [Card].
38+
*
39+
* @param defaultElevation the elevation used when the [Card] is has no other [Interaction]s.
40+
* @param pressedElevation the elevation used when the [Card] is pressed.
41+
* @param focusedElevation the elevation used when the [Card] is focused.
42+
* @param hoveredElevation the elevation used when the [Card] is hovered.
43+
* @param draggedElevation the elevation used when the [Card] is dragged.
44+
*/
45+
@Composable
46+
fun cardElevation(
47+
defaultElevation: Dp = MainTheme.elevations.level0,
48+
pressedElevation: Dp = MainTheme.elevations.level0,
49+
focusedElevation: Dp = MainTheme.elevations.level0,
50+
hoveredElevation: Dp = MainTheme.elevations.level1,
51+
draggedElevation: Dp = MainTheme.elevations.level3,
52+
disabledElevation: Dp = MainTheme.elevations.level0,
53+
): CardElevation = CardElevation.FilledCardElevation(
54+
defaultElevation = defaultElevation,
55+
pressedElevation = pressedElevation,
56+
focusedElevation = focusedElevation,
57+
hoveredElevation = hoveredElevation,
58+
draggedElevation = draggedElevation,
59+
disabledElevation = disabledElevation,
60+
)
61+
62+
/**
63+
* Creates a [CardElevation] that will animate between the provided values according to the
64+
* Material specification for an [ElevatedCard].
65+
*
66+
* @param defaultElevation the elevation used when the [ElevatedCard] is has no other
67+
* [Interaction]s.
68+
* @param pressedElevation the elevation used when the [ElevatedCard] is pressed.
69+
* @param focusedElevation the elevation used when the [ElevatedCard] is focused.
70+
* @param hoveredElevation the elevation used when the [ElevatedCard] is hovered.
71+
* @param draggedElevation the elevation used when the [ElevatedCard] is dragged.
72+
*/
73+
@Composable
74+
fun elevatedCardElevation(
75+
defaultElevation: Dp = MainTheme.elevations.level1,
76+
pressedElevation: Dp = MainTheme.elevations.level1,
77+
focusedElevation: Dp = MainTheme.elevations.level1,
78+
hoveredElevation: Dp = MainTheme.elevations.level2,
79+
draggedElevation: Dp = MainTheme.elevations.level4,
80+
disabledElevation: Dp = MainTheme.elevations.level1,
81+
): CardElevation = CardElevation.ElevatedCardElevation(
82+
defaultElevation = defaultElevation,
83+
pressedElevation = pressedElevation,
84+
focusedElevation = focusedElevation,
85+
hoveredElevation = hoveredElevation,
86+
draggedElevation = draggedElevation,
87+
disabledElevation = disabledElevation,
88+
)
89+
90+
/**
91+
* Creates a [CardElevation] that will animate between the provided values according to the
92+
* Material specification for an [OutlinedCard].
93+
*
94+
* @param defaultElevation the elevation used when the [OutlinedCard] is has no other
95+
* [Interaction]s.
96+
* @param pressedElevation the elevation used when the [OutlinedCard] is pressed.
97+
* @param focusedElevation the elevation used when the [OutlinedCard] is focused.
98+
* @param hoveredElevation the elevation used when the [OutlinedCard] is hovered.
99+
* @param draggedElevation the elevation used when the [OutlinedCard] is dragged.
100+
*/
101+
@Composable
102+
fun outlinedCardElevation(
103+
defaultElevation: Dp = MainTheme.elevations.level0,
104+
pressedElevation: Dp = defaultElevation,
105+
focusedElevation: Dp = defaultElevation,
106+
hoveredElevation: Dp = defaultElevation,
107+
draggedElevation: Dp = MainTheme.elevations.level3,
108+
disabledElevation: Dp = MainTheme.elevations.level0,
109+
): CardElevation = CardElevation.OutlinedCardElevation(
110+
defaultElevation = defaultElevation,
111+
pressedElevation = pressedElevation,
112+
focusedElevation = focusedElevation,
113+
hoveredElevation = hoveredElevation,
114+
draggedElevation = draggedElevation,
115+
disabledElevation = disabledElevation,
116+
)
117+
118+
/**
119+
* Creates a [CardColors] that represents the default container and content colors used in a
120+
* [Card].
121+
*/
122+
@Composable
123+
fun cardColors(): CardColors = Material3CardDefaults.cardColors().toCardColors()
124+
125+
/**
126+
* Creates a [CardColors] that represents the default container and content colors used in a
127+
* [Card].
128+
*
129+
* @param containerColor the container color of this [Card] when enabled.
130+
* @param contentColor the content color of this [Card] when enabled.
131+
* @param disabledContainerColor the container color of this [Card] when not enabled.
132+
* @param disabledContentColor the content color of this [Card] when not enabled.
133+
*/
134+
@Composable
135+
fun cardColors(
136+
containerColor: Color = Color.Unspecified,
137+
contentColor: Color = contentColorFor(backgroundColor = containerColor),
138+
disabledContainerColor: Color = Color.Unspecified,
139+
disabledContentColor: Color = contentColor.copy(alpha = DISABLED_ALPHA),
140+
): CardColors = Material3CardDefaults.cardColors(
141+
containerColor = containerColor,
142+
contentColor = contentColor,
143+
disabledContainerColor = disabledContainerColor,
144+
disabledContentColor = disabledContentColor,
145+
).toCardColors()
146+
147+
/**
148+
* Creates a [CardColors] that represents the default container and content colors used in an
149+
* [ElevatedCard].
150+
*/
151+
@Composable
152+
fun elevatedCardColors(): CardColors = Material3CardDefaults.elevatedCardColors().toCardColors()
153+
154+
/**
155+
* Creates a [CardColors] that represents the default container and content colors used in an
156+
* [ElevatedCard].
157+
*
158+
* @param containerColor the container color of this [ElevatedCard] when enabled.
159+
* @param contentColor the content color of this [ElevatedCard] when enabled.
160+
* @param disabledContainerColor the container color of this [ElevatedCard] when not enabled.
161+
* @param disabledContentColor the content color of this [ElevatedCard] when not enabled.
162+
*/
163+
@Composable
164+
fun elevatedCardColors(
165+
containerColor: Color = Color.Unspecified,
166+
contentColor: Color = contentColorFor(backgroundColor = containerColor),
167+
disabledContainerColor: Color = Color.Unspecified,
168+
disabledContentColor: Color = contentColor.copy(alpha = DISABLED_ALPHA),
169+
): CardColors = Material3CardDefaults.elevatedCardColors(
170+
containerColor = containerColor,
171+
contentColor = contentColor,
172+
disabledContainerColor = disabledContainerColor,
173+
disabledContentColor = disabledContentColor,
174+
).toCardColors()
175+
176+
/**
177+
* Creates a [CardColors] that represents the default container and content colors used in an
178+
* [OutlinedCard].
179+
*/
180+
@Composable
181+
fun outlinedCardColors(): CardColors = Material3CardDefaults.outlinedCardColors().toCardColors()
182+
183+
/**
184+
* Creates a [CardColors] that represents the default container and content colors used in an
185+
* [OutlinedCard].
186+
*
187+
* @param containerColor the container color of this [OutlinedCard] when enabled.
188+
* @param contentColor the content color of this [OutlinedCard] when enabled.
189+
* @param disabledContainerColor the container color of this [OutlinedCard] when not enabled.
190+
* @param disabledContentColor the content color of this [OutlinedCard] when not enabled.
191+
*/
192+
@Composable
193+
fun outlinedCardColors(
194+
containerColor: Color = Color.Unspecified,
195+
contentColor: Color = contentColorFor(backgroundColor = containerColor),
196+
disabledContainerColor: Color = Color.Unspecified,
197+
disabledContentColor: Color = contentColorFor(backgroundColor = containerColor).copy(alpha = DISABLED_ALPHA),
198+
): CardColors = Material3CardDefaults.outlinedCardColors(
199+
containerColor = containerColor,
200+
contentColor = contentColor,
201+
disabledContainerColor = disabledContainerColor,
202+
disabledContentColor = disabledContentColor,
203+
).toCardColors()
204+
205+
/**
206+
* Creates a [BorderStroke] that represents the default border used in [OutlinedCard].
207+
*
208+
* @param enabled whether the card is enabled
209+
*/
210+
@Composable
211+
fun outlinedCardBorder(enabled: Boolean = true): BorderStroke =
212+
Material3CardDefaults.outlinedCardBorder(enabled)
213+
}

0 commit comments

Comments
 (0)