Skip to content

Commit

Permalink
feat(style-speakers): create LabeledSpeakersAvatar component.
Browse files Browse the repository at this point in the history
  • Loading branch information
GerardPaligot committed Oct 21, 2023
1 parent 19e2ef1 commit c43a670
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 41 deletions.
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
package org.gdglille.devfest.android.theme.m3.schedules.ui.speakers

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import org.gdglille.devfest.android.theme.m3.style.Conferences4HallTheme
import org.gdglille.devfest.android.theme.m3.style.R
import org.gdglille.devfest.android.theme.m3.style.speakers.avatars.SmallBorderedSpeakersAvatar
import org.gdglille.devfest.android.theme.m3.style.speakers.avatars.SmallLabeledSpeakersAvatar
import org.gdglille.devfest.models.ui.TalkItemUi

private const val MaxSpeakersCount = 3
Expand All @@ -28,37 +21,25 @@ fun HorizontalSpeakersList(
) {
val count = (names.size - MaxSpeakersCount).coerceAtLeast(minimumValue = 0)
val speakers = names.take(MaxSpeakersCount).joinToString(", ")
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
SmallLabeledSpeakersAvatar(
label = if (count == 0) speakers else pluralStringResource(
id = R.plurals.text_speakers_list,
count = count,
speakers,
count
),
urls = avatars.take(MaxSpeakersCount).toImmutableList(),
modifier = modifier
) {
SmallBorderedSpeakersAvatar(
urls = avatars.take(MaxSpeakersCount).toImmutableList(),
descriptions = names.take(MaxSpeakersCount).toImmutableList()
)
Text(
text = if (count == 0) speakers else pluralStringResource(
id = R.plurals.text_speakers_list,
count = count,
speakers,
count
),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface
)
}
)
}

@Preview(showBackground = true)
@Composable
private fun HorizontalSpeakersListPreview() {
Conferences4HallTheme {
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
HorizontalSpeakersList(
names = TalkItemUi.fake.speakers,
avatars = TalkItemUi.fake.speakersAvatar
)
}
HorizontalSpeakersList(
names = TalkItemUi.fake.speakers,
avatars = TalkItemUi.fake.speakersAvatar
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.gdglille.devfest.android.theme.m3.style.speakers.avatars

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import org.gdglille.devfest.android.theme.m3.style.Conferences4HallTheme

@Composable
fun SmallLabeledSpeakersAvatar(
label: String,
urls: ImmutableList<String>,
modifier: Modifier = Modifier,
color: Color = LabeledSpeakersAvatarDefaults.contentColor,
style: TextStyle = LabeledSpeakersAvatarDefaults.smallTextStyle
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(LabeledSpeakersAvatarSizingTokens.SmallSpacing.toDp()),
modifier = modifier
) {
SmallBorderedSpeakersAvatar(urls = urls, descriptions = null)
Text(text = label, style = style, color = color)
}
}

@Preview(showBackground = true)
@Composable
private fun HorizontalSpeakersListPreview() {
Conferences4HallTheme {
SmallLabeledSpeakersAvatar(
label = "John Doe and Janne Doe",
urls = persistentListOf("", "")
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.gdglille.devfest.android.theme.m3.style.speakers.avatars

import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.graphics.Color

enum class LabeledSpeakersAvatarColorTokens {
OnSurface
}

internal fun ColorScheme.fromToken(value: LabeledSpeakersAvatarColorTokens): Color {
return when (value) {
LabeledSpeakersAvatarColorTokens.OnSurface -> onSurface
}
}

@Composable
@ReadOnlyComposable
internal fun LabeledSpeakersAvatarColorTokens.toColor(): Color {
return MaterialTheme.colorScheme.fromToken(this)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.gdglille.devfest.android.theme.m3.style.speakers.avatars

import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle

object LabeledSpeakersAvatarDefaults {
val smallTextStyle: TextStyle
@Composable
get() = LabeledSpeakersAvatarSmallTokens.LabelTextStyle.toTextStyle()

val contentColor: Color
@Composable
get() = LabeledSpeakersAvatarSmallTokens.ContentColor.toColor()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.gdglille.devfest.android.theme.m3.style.speakers.avatars

import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

enum class LabeledSpeakersAvatarSizingTokens {
SmallSpacing
}

internal fun fromToken(value: LabeledSpeakersAvatarSizingTokens): Dp {
return when (value) {
LabeledSpeakersAvatarSizingTokens.SmallSpacing -> 8.dp
}
}

@Composable
@ReadOnlyComposable
internal fun LabeledSpeakersAvatarSizingTokens.toDp(): Dp {
return fromToken(this)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.gdglille.devfest.android.theme.m3.style.speakers.avatars

internal object LabeledSpeakersAvatarSmallTokens {
val ContentColor = LabeledSpeakersAvatarColorTokens.OnSurface
val LabelTextStyle = LabeledSpeakersAvatarTextStyleTokens.BodyMedium
val SpacingBetween = LabeledSpeakersAvatarSizingTokens.SmallSpacing
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.gdglille.devfest.android.theme.m3.style.speakers.avatars

import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Typography
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.text.TextStyle

enum class LabeledSpeakersAvatarTextStyleTokens {
BodyMedium
}

internal fun Typography.fromToken(value: LabeledSpeakersAvatarTextStyleTokens): TextStyle {
return when (value) {
LabeledSpeakersAvatarTextStyleTokens.BodyMedium -> bodyMedium
}
}

@Composable
@ReadOnlyComposable
internal fun LabeledSpeakersAvatarTextStyleTokens.toTextStyle(): TextStyle {
return MaterialTheme.typography.fromToken(this)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ import org.gdglille.devfest.android.theme.m3.style.speakers.avatar.SmallBordered
@Composable
fun SmallBorderedSpeakersAvatar(
urls: ImmutableList<String>,
descriptions: ImmutableList<String>,
descriptions: ImmutableList<String>?,
modifier: Modifier = Modifier,
) {
require(urls.size == descriptions.size) {
"Urls and descriptions arrays should have the exact same size."
if (descriptions != null) {
require(urls.size == descriptions.size) {
"Urls and descriptions arrays should have the exact same size."
}
}
val height = BorderedSpeakerAvatarSmallTokens.ContainerHeight.value
val spacingPx = with(LocalDensity.current) { 4.dp.toPx() }
Expand All @@ -34,7 +36,7 @@ fun SmallBorderedSpeakersAvatar(
Box(modifier = modifierPadding) {
SmallBorderedSpeakerAvatar(
url = url,
contentDescription = descriptions[index]
contentDescription = descriptions?.getOrNull(index)
)
}
}
Expand All @@ -44,11 +46,13 @@ fun SmallBorderedSpeakersAvatar(
@Composable
fun MediumBorderedSpeakersAvatar(
urls: ImmutableList<String>,
descriptions: ImmutableList<String>,
descriptions: ImmutableList<String>?,
modifier: Modifier = Modifier,
) {
require(urls.size == descriptions.size) {
"Urls and descriptions arrays should have the exact same size."
if (descriptions != null) {
require(urls.size == descriptions.size) {
"Urls and descriptions arrays should have the exact same size."
}
}
val height = BorderedSpeakerAvatarMediumTokens.ContainerHeight.value
val spacingPx = with(LocalDensity.current) { 4.dp.toPx() }
Expand All @@ -59,7 +63,7 @@ fun MediumBorderedSpeakersAvatar(
Box(modifier = modifierPadding) {
MediumBorderedSpeakerAvatar(
url = url,
contentDescription = descriptions[index]
contentDescription = descriptions?.getOrNull(index)
)
}
}
Expand Down

0 comments on commit c43a670

Please sign in to comment.