Merge pull request #4921 from element-hq/feature/bma/spaceAvatar

Iterate on avatar to be able to render Space avatar.
This commit is contained in:
Benoit Marty 2025-06-23 19:01:33 +02:00 committed by GitHub
commit ebda14b37b
28 changed files with 437 additions and 149 deletions

View file

@ -40,6 +40,7 @@ import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtom
import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtomSize import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtomSize
import io.element.android.libraries.designsystem.components.async.AsyncActionView import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.list.ListItemContent import io.element.android.libraries.designsystem.components.list.ListItemContent
import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap
@ -219,6 +220,7 @@ private fun RoomNameWithAvatar(
) { ) {
UnsavedAvatar( UnsavedAvatar(
avatarUri = avatarUri, avatarUri = avatarUri,
avatarType = AvatarType.Room(),
modifier = Modifier.clickable(onClick = onAvatarClick), modifier = Modifier.clickable(onClick = onAvatarClick),
) )

View file

@ -53,6 +53,7 @@ import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.components.async.AsyncActionView import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.avatar.Avatar import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.button.SuperButton import io.element.android.libraries.designsystem.components.button.SuperButton
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
@ -92,7 +93,11 @@ fun JoinRoomView(
vertical = 32.dp vertical = 32.dp
), ),
topBar = { topBar = {
JoinRoomTopBar(contentState = state.contentState, onBackClick = onBackClick) JoinRoomTopBar(
contentState = state.contentState,
hideAvatarImage = state.hideAvatarsImages,
onBackClick = onBackClick,
)
}, },
content = { content = {
JoinRoomContent( JoinRoomContent(
@ -490,7 +495,11 @@ private fun DefaultLoadedContent(
RoomPreviewOrganism( RoomPreviewOrganism(
modifier = modifier, modifier = modifier,
avatar = { avatar = {
Avatar(contentState.avatarData(AvatarSize.RoomHeader), hideImage = hideAvatarImage) Avatar(
contentState.avatarData(AvatarSize.RoomHeader),
hideImage = hideAvatarImage,
avatarType = AvatarType.Room(),
)
}, },
title = { title = {
if (contentState.name != null) { if (contentState.name != null) {
@ -545,6 +554,7 @@ private fun DefaultLoadedContent(
@Composable @Composable
private fun JoinRoomTopBar( private fun JoinRoomTopBar(
contentState: ContentState, contentState: ContentState,
hideAvatarImage: Boolean,
onBackClick: () -> Unit, onBackClick: () -> Unit,
) { ) {
TopAppBar( TopAppBar(
@ -561,7 +571,11 @@ private fun JoinRoomTopBar(
modifier = titleModifier, modifier = titleModifier,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Avatar(avatarData = contentState.avatarData(AvatarSize.TimelineRoom)) Avatar(
avatarData = contentState.avatarData(AvatarSize.TimelineRoom),
hideImage = hideAvatarImage,
avatarType = AvatarType.Room(),
)
Text( Text(
modifier = Modifier.padding(horizontal = 8.dp), modifier = Modifier.padding(horizontal = 8.dp),
text = contentState.name, text = contentState.name,

View file

@ -83,8 +83,9 @@ import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorVi
import io.element.android.features.roomcall.api.RoomCallState import io.element.android.features.roomcall.api.RoomCallState
import io.element.android.libraries.androidutils.ui.hideKeyboard import io.element.android.libraries.androidutils.ui.hideKeyboard
import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertMolecule import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertMolecule
import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.RoomAvatar import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
@ -563,10 +564,12 @@ private fun RoomAvatarAndNameRow(
modifier = modifier, modifier = modifier,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
RoomAvatar( Avatar(
avatarData = roomAvatar, avatarData = roomAvatar,
heroes = heroes, avatarType = AvatarType.Room(
isTombstoned = isTombstoned, heroes = heroes,
isTombstoned = isTombstoned,
),
) )
Text( Text(
modifier = Modifier.padding(horizontal = 8.dp), modifier = Modifier.padding(horizontal = 8.dp),

View file

@ -27,6 +27,7 @@ import io.element.android.features.messages.impl.R
import io.element.android.libraries.designsystem.components.avatar.Avatar import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.components.avatar.anAvatarData import io.element.android.libraries.designsystem.components.avatar.anAvatarData
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@ -98,6 +99,11 @@ private fun SuggestionItemView(
is ResolvedSuggestion.Member -> suggestion.roomMember.getAvatarData(avatarSize) is ResolvedSuggestion.Member -> suggestion.roomMember.getAvatarData(avatarSize)
is ResolvedSuggestion.Alias -> suggestion.getAvatarData(avatarSize) is ResolvedSuggestion.Alias -> suggestion.getAvatarData(avatarSize)
} }
val avatarType = when (suggestion) {
is ResolvedSuggestion.Alias -> AvatarType.Room()
ResolvedSuggestion.AtRoom,
is ResolvedSuggestion.Member -> AvatarType.User
}
val title = when (suggestion) { val title = when (suggestion) {
is ResolvedSuggestion.AtRoom -> stringResource(R.string.screen_room_mentions_at_room_title) is ResolvedSuggestion.AtRoom -> stringResource(R.string.screen_room_mentions_at_room_title)
is ResolvedSuggestion.Member -> suggestion.roomMember.displayName is ResolvedSuggestion.Member -> suggestion.roomMember.displayName
@ -108,9 +114,11 @@ private fun SuggestionItemView(
is ResolvedSuggestion.Member -> suggestion.roomMember.userId.value is ResolvedSuggestion.Member -> suggestion.roomMember.userId.value
is ResolvedSuggestion.Alias -> suggestion.roomAlias.value is ResolvedSuggestion.Alias -> suggestion.roomAlias.value
} }
Avatar(
Avatar(avatarData = avatarData, modifier = Modifier.padding(start = 16.dp, top = 12.dp, bottom = 12.dp)) avatarData = avatarData,
avatarType = avatarType,
modifier = Modifier.padding(start = 16.dp, top = 12.dp, bottom = 12.dp),
)
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()

View file

@ -16,7 +16,8 @@ import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.features.preferences.impl.R import io.element.android.features.preferences.impl.R
import io.element.android.libraries.designsystem.components.async.AsyncActionView import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.avatar.RoomAvatar import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.components.list.ListItemContent import io.element.android.libraries.designsystem.components.list.ListItemContent
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
import io.element.android.libraries.designsystem.components.preferences.PreferencePage import io.element.android.libraries.designsystem.components.preferences.PreferencePage
@ -97,9 +98,11 @@ fun EditDefaultNotificationSettingView(
Text(text = subtitle) Text(text = subtitle)
}, },
leadingContent = ListItemContent.Custom { leadingContent = ListItemContent.Custom {
RoomAvatar( Avatar(
avatarData = summary.avatarData, avatarData = summary.avatarData,
heroes = summary.heroesAvatar, avatarType = AvatarType.Room(
heroes = summary.heroesAvatar,
),
) )
}, },
onClick = { onClick = {

View file

@ -32,6 +32,7 @@ import io.element.android.features.preferences.impl.R
import io.element.android.libraries.designsystem.components.async.AsyncActionView import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
@ -101,6 +102,7 @@ fun EditUserProfileView(
displayName = state.displayName, displayName = state.displayName,
avatarUrl = state.userAvatarUrl, avatarUrl = state.userAvatarUrl,
avatarSize = AvatarSize.EditProfileDetails, avatarSize = AvatarSize.EditProfileDetails,
avatarType = AvatarType.User,
onAvatarClick = { onAvatarClick() }, onAvatarClick = { onAvatarClick() },
modifier = Modifier.align(Alignment.CenterHorizontally), modifier = Modifier.align(Alignment.CenterHorizontally),
) )

View file

@ -48,10 +48,11 @@ import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage
import io.element.android.libraries.designsystem.atomic.atoms.MatrixBadgeAtom import io.element.android.libraries.designsystem.atomic.atoms.MatrixBadgeAtom
import io.element.android.libraries.designsystem.atomic.molecules.MatrixBadgeRowMolecule import io.element.android.libraries.designsystem.atomic.molecules.MatrixBadgeRowMolecule
import io.element.android.libraries.designsystem.components.ClickableLinkText import io.element.android.libraries.designsystem.components.ClickableLinkText
import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.components.avatar.DmAvatars import io.element.android.libraries.designsystem.components.avatar.DmAvatars
import io.element.android.libraries.designsystem.components.avatar.RoomAvatar
import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.button.MainActionButton import io.element.android.libraries.designsystem.components.button.MainActionButton
import io.element.android.libraries.designsystem.components.list.ListItemContent import io.element.android.libraries.designsystem.components.list.ListItemContent
@ -399,12 +400,14 @@ private fun RoomHeaderSection(
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
RoomAvatar( Avatar(
avatarData = AvatarData(roomId.value, roomName, avatarUrl, AvatarSize.RoomHeader), avatarData = AvatarData(roomId.value, roomName, avatarUrl, AvatarSize.RoomHeader),
heroes = heroes.map { user -> avatarType = AvatarType.Room(
user.getAvatarData(size = AvatarSize.RoomHeader) heroes = heroes.map { user ->
}.toPersistentList(), user.getAvatarData(size = AvatarSize.RoomHeader)
isTombstoned = isTombstoned, }.toPersistentList(),
isTombstoned = isTombstoned,
),
modifier = Modifier modifier = Modifier
.clickable(enabled = avatarUrl != null) { openAvatarPreview(avatarUrl!!) } .clickable(enabled = avatarUrl != null) { openAvatarPreview(avatarUrl!!) }
.testTag(TestTags.roomDetailAvatar) .testTag(TestTags.roomDetailAvatar)

View file

@ -34,6 +34,7 @@ import io.element.android.features.roomdetails.impl.R
import io.element.android.libraries.designsystem.components.async.AsyncActionView import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
@ -103,6 +104,7 @@ fun RoomDetailsEditView(
displayName = state.roomRawName, displayName = state.roomRawName,
avatarUrl = state.roomAvatarUrl, avatarUrl = state.roomAvatarUrl,
avatarSize = AvatarSize.EditRoomDetails, avatarSize = AvatarSize.EditRoomDetails,
avatarType = AvatarType.Room(),
onAvatarClick = ::onAvatarClick, onAvatarClick = ::onAvatarClick,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) )

View file

@ -40,6 +40,7 @@ import io.element.android.features.roomdirectory.api.RoomDescription
import io.element.android.features.roomdirectory.impl.R import io.element.android.features.roomdirectory.impl.R
import io.element.android.libraries.designsystem.components.avatar.Avatar import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@ -248,7 +249,8 @@ private fun RoomDirectoryRoomRow(
) { ) {
Avatar( Avatar(
avatarData = roomDescription.avatarData(AvatarSize.RoomDirectoryItem), avatarData = roomDescription.avatarData(AvatarSize.RoomDirectoryItem),
modifier = Modifier.align(Alignment.CenterVertically) avatarType = AvatarType.Room(),
modifier = Modifier.align(Alignment.CenterVertically),
) )
Column( Column(
modifier = Modifier modifier = Modifier

View file

@ -44,7 +44,8 @@ import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryProvid
import io.element.android.features.roomlist.impl.model.RoomSummaryDisplayType import io.element.android.features.roomlist.impl.model.RoomSummaryDisplayType
import io.element.android.libraries.core.extensions.orEmpty import io.element.android.libraries.core.extensions.orEmpty
import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAtom import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAtom
import io.element.android.libraries.designsystem.components.avatar.RoomAvatar import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Button
@ -184,11 +185,13 @@ private fun RoomSummaryScaffoldRow(
.padding(horizontal = 16.dp, vertical = 11.dp) .padding(horizontal = 16.dp, vertical = 11.dp)
.height(IntrinsicSize.Min), .height(IntrinsicSize.Min),
) { ) {
RoomAvatar( Avatar(
avatarData = room.avatarData, avatarData = room.avatarData,
heroes = room.heroes, avatarType = AvatarType.Room(
isTombstoned = room.isTombstoned, heroes = room.heroes,
hideAvatarImage = hideAvatarImage, isTombstoned = room.isTombstoned,
),
hideImage = hideAvatarImage,
) )
Spacer(modifier = Modifier.width(16.dp)) Spacer(modifier = Modifier.width(16.dp))
Column( Column(

View file

@ -9,43 +9,66 @@ package io.element.android.libraries.designsystem.components.avatar
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImagePainter
import coil3.compose.SubcomposeAsyncImage
import coil3.compose.SubcomposeAsyncImageContent
import io.element.android.libraries.designsystem.colors.AvatarColorsProvider
import io.element.android.libraries.designsystem.preview.ElementThemedPreview import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup import io.element.android.libraries.designsystem.preview.PreviewGroup
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.utils.CommonDrawables import io.element.android.libraries.designsystem.utils.CommonDrawables
import timber.log.Timber
@Composable @Composable
fun Avatar( fun Avatar(
avatarData: AvatarData, avatarData: AvatarData,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
avatarType: AvatarType = AvatarType.User,
contentDescription: String? = null, contentDescription: String? = null,
// If not null, will be used instead of the size from avatarData // If not null, will be used instead of the size from avatarData
forcedAvatarSize: Dp? = null, forcedAvatarSize: Dp? = null,
// If true, will show initials even if avatarData.url is not null // If true, will show initials even if avatarData.url is not null
hideImage: Boolean = false, hideImage: Boolean = false,
) {
when (avatarType) {
is AvatarType.Room -> RoomAvatar(
avatarData = avatarData,
avatarType = avatarType,
modifier = modifier,
hideAvatarImage = hideImage,
contentDescription = contentDescription,
)
AvatarType.User -> UserAvatar(
avatarData = avatarData,
modifier = modifier,
contentDescription = contentDescription,
forcedAvatarSize = forcedAvatarSize,
hideImage = hideImage,
)
is AvatarType.Space -> SpaceAvatar(
avatarData = avatarData,
avatarType = avatarType,
modifier = modifier,
hideAvatarImage = hideImage,
contentDescription = contentDescription,
)
}
}
@Composable
private fun UserAvatar(
avatarData: AvatarData,
modifier: Modifier = Modifier,
contentDescription: String? = null,
forcedAvatarSize: Dp? = null,
hideImage: Boolean = false,
) { ) {
if (avatarData.url.isNullOrBlank() || hideImage) { if (avatarData.url.isNullOrBlank() || hideImage) {
InitialLetterAvatar( InitialLetterAvatar(
avatarData = avatarData, avatarData = avatarData,
avatarType = AvatarType.User,
forcedAvatarSize = forcedAvatarSize, forcedAvatarSize = forcedAvatarSize,
modifier = modifier, modifier = modifier,
contentDescription = contentDescription, contentDescription = contentDescription,
@ -53,6 +76,7 @@ fun Avatar(
} else { } else {
ImageAvatar( ImageAvatar(
avatarData = avatarData, avatarData = avatarData,
avatarType = AvatarType.User,
forcedAvatarSize = forcedAvatarSize, forcedAvatarSize = forcedAvatarSize,
modifier = modifier, modifier = modifier,
contentDescription = contentDescription, contentDescription = contentDescription,
@ -60,61 +84,6 @@ fun Avatar(
} }
} }
@Composable
private fun ImageAvatar(
avatarData: AvatarData,
forcedAvatarSize: Dp?,
modifier: Modifier = Modifier,
contentDescription: String? = null,
) {
val size = forcedAvatarSize ?: avatarData.size.dp
SubcomposeAsyncImage(
model = avatarData,
contentDescription = contentDescription,
contentScale = ContentScale.Crop,
modifier = modifier
.size(size)
.clip(CircleShape)
) {
val collectedState by painter.state.collectAsState()
when (val state = collectedState) {
is AsyncImagePainter.State.Success -> SubcomposeAsyncImageContent()
is AsyncImagePainter.State.Error -> {
SideEffect {
Timber.e(state.result.throwable, "Error loading avatar $state\n${state.result}")
}
InitialLetterAvatar(
avatarData = avatarData,
forcedAvatarSize = forcedAvatarSize,
contentDescription = contentDescription,
)
}
else -> InitialLetterAvatar(
avatarData = avatarData,
forcedAvatarSize = forcedAvatarSize,
contentDescription = contentDescription,
)
}
}
}
@Composable
private fun InitialLetterAvatar(
avatarData: AvatarData,
forcedAvatarSize: Dp?,
contentDescription: String?,
modifier: Modifier = Modifier,
) {
val avatarColors = AvatarColorsProvider.provide(avatarData.id)
TextAvatar(
text = avatarData.initialLetter,
size = forcedAvatarSize ?: avatarData.size.dp,
colors = avatarColors,
contentDescription = contentDescription,
modifier = modifier
)
}
@Preview(group = PreviewGroup.Avatars) @Preview(group = PreviewGroup.Avatars)
@Composable @Composable
internal fun AvatarPreview(@PreviewParameter(AvatarDataProvider::class) avatarData: AvatarData) = internal fun AvatarPreview(@PreviewParameter(AvatarDataProvider::class) avatarData: AvatarData) =

View file

@ -31,9 +31,10 @@ import kotlin.math.sin
private const val MAX_AVATAR_COUNT = 4 private const val MAX_AVATAR_COUNT = 4
@Composable @Composable
fun AvatarCluster( internal fun AvatarCluster(
avatars: ImmutableList<AvatarData>, avatars: ImmutableList<AvatarData>,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
avatarType: AvatarType = AvatarType.User,
hideAvatarImages: Boolean = false, hideAvatarImages: Boolean = false,
contentDescription: String? = null, contentDescription: String? = null,
) { ) {
@ -50,6 +51,7 @@ fun AvatarCluster(
1 -> { 1 -> {
Avatar( Avatar(
avatarData = limitedAvatars[0], avatarData = limitedAvatars[0],
avatarType = avatarType,
modifier = modifier, modifier = modifier,
contentDescription = contentDescription, contentDescription = contentDescription,
hideImage = hideAvatarImages hideImage = hideAvatarImages
@ -78,10 +80,10 @@ fun AvatarCluster(
} }
Box( Box(
modifier = modifier modifier = modifier
.size(size.dp) .size(size.dp)
.semantics { .semantics {
this.contentDescription = contentDescription.orEmpty() this.contentDescription = contentDescription.orEmpty()
}, },
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
limitedAvatars.forEachIndexed { index, heroAvatar -> limitedAvatars.forEachIndexed { index, heroAvatar ->
@ -89,15 +91,16 @@ fun AvatarCluster(
val yOffset = (offsetRadius * sin(angle * index.toDouble() + angleOffset)).dp val yOffset = (offsetRadius * sin(angle * index.toDouble() + angleOffset)).dp
Box( Box(
modifier = Modifier modifier = Modifier
.size(heroAvatarSize) .size(heroAvatarSize)
.offset( .offset(
x = xOffset, x = xOffset,
y = yOffset, y = yOffset,
) )
) { ) {
Avatar( Avatar(
avatarData = heroAvatar, avatarData = heroAvatar,
forcedAvatarSize = heroAvatarSize, forcedAvatarSize = heroAvatarSize,
avatarType = avatarType,
hideImage = hideAvatarImages, hideImage = hideAvatarImages,
) )
} }

View file

@ -0,0 +1,22 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.designsystem.components.avatar
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Shape
@Composable
fun AvatarType.avatarShape(): Shape {
return when (this) {
is AvatarType.Space -> RoundedCornerShape(cornerSize)
is AvatarType.Room,
AvatarType.User -> CircleShape
}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.designsystem.components.avatar
import androidx.compose.runtime.Immutable
import androidx.compose.ui.unit.Dp
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@Immutable
sealed interface AvatarType {
data object User : AvatarType
data class Room(
val isTombstoned: Boolean = false,
val heroes: ImmutableList<AvatarData> = persistentListOf(),
) : AvatarType
data class Space(
val cornerSize: Dp,
val isTombstoned: Boolean = false,
) : AvatarType
}

View file

@ -0,0 +1,66 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.designsystem.components.avatar
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.Dp
import coil3.compose.AsyncImagePainter
import coil3.compose.SubcomposeAsyncImage
import coil3.compose.SubcomposeAsyncImageContent
import timber.log.Timber
@Composable
internal fun ImageAvatar(
avatarData: AvatarData,
avatarType: AvatarType,
forcedAvatarSize: Dp?,
modifier: Modifier = Modifier.Companion,
contentDescription: String? = null,
) {
val size = forcedAvatarSize ?: avatarData.size.dp
SubcomposeAsyncImage(
model = avatarData,
contentDescription = contentDescription,
contentScale = ContentScale.Companion.Crop,
modifier = modifier
.size(size)
.clip(avatarType.avatarShape())
) {
val collectedState by painter.state.collectAsState()
when (val state = collectedState) {
is AsyncImagePainter.State.Success -> SubcomposeAsyncImageContent()
is AsyncImagePainter.State.Error -> {
SideEffect {
Timber.Forest.e(
state.result.throwable,
"Error loading avatar $state\n${state.result}"
)
}
InitialLetterAvatar(
avatarData = avatarData,
avatarType = avatarType,
forcedAvatarSize = forcedAvatarSize,
contentDescription = contentDescription,
)
}
else -> InitialLetterAvatar(
avatarData = avatarData,
avatarType = avatarType,
forcedAvatarSize = forcedAvatarSize,
contentDescription = contentDescription,
)
}
}
}

View file

@ -0,0 +1,32 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.designsystem.components.avatar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import io.element.android.libraries.designsystem.colors.AvatarColorsProvider
@Composable
internal fun InitialLetterAvatar(
avatarData: AvatarData,
avatarType: AvatarType,
forcedAvatarSize: Dp?,
contentDescription: String?,
modifier: Modifier = Modifier.Companion,
) {
val avatarColors = AvatarColorsProvider.provide(avatarData.id)
TextAvatar(
text = avatarData.initialLetter,
size = forcedAvatarSize ?: avatarData.size.dp,
avatarType = avatarType,
colors = avatarColors,
contentDescription = contentDescription,
modifier = modifier
)
}

View file

@ -9,36 +9,46 @@ package io.element.android.libraries.designsystem.components.avatar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import kotlinx.collections.immutable.ImmutableList
@Composable @Composable
fun RoomAvatar( internal fun RoomAvatar(
avatarData: AvatarData, avatarData: AvatarData,
heroes: ImmutableList<AvatarData>, avatarType: AvatarType.Room,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
isTombstoned: Boolean = false,
hideAvatarImage: Boolean = false, hideAvatarImage: Boolean = false,
contentDescription: String? = null, contentDescription: String? = null,
) { ) {
when { when {
isTombstoned -> { avatarType.isTombstoned -> {
TombstonedRoomAvatar( TombstonedRoomAvatar(
size = avatarData.size, size = avatarData.size,
modifier = modifier, modifier = modifier,
avatarType = avatarType,
contentDescription = contentDescription contentDescription = contentDescription
) )
} }
avatarData.url != null || heroes.isEmpty() -> { avatarData.url != null || avatarType.heroes.isEmpty() -> {
Avatar( if (avatarData.url.isNullOrBlank() || hideAvatarImage) {
avatarData = avatarData, InitialLetterAvatar(
modifier = modifier, avatarData = avatarData,
contentDescription = contentDescription, avatarType = avatarType,
hideImage = hideAvatarImage modifier = modifier,
) contentDescription = contentDescription,
forcedAvatarSize = null,
)
} else {
ImageAvatar(
avatarData = avatarData,
avatarType = avatarType,
forcedAvatarSize = null,
modifier = modifier,
contentDescription = contentDescription,
)
}
} }
else -> { else -> {
AvatarCluster( AvatarCluster(
avatars = heroes, avatars = avatarType.heroes,
modifier = modifier, modifier = modifier,
hideAvatarImages = hideAvatarImage, hideAvatarImages = hideAvatarImage,
contentDescription = contentDescription contentDescription = contentDescription

View file

@ -0,0 +1,75 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.designsystem.components.avatar
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
import io.element.android.libraries.designsystem.utils.CommonDrawables
@Composable
fun SpaceAvatar(
avatarData: AvatarData,
avatarType: AvatarType.Space,
modifier: Modifier = Modifier,
hideAvatarImage: Boolean = false,
contentDescription: String? = null,
) {
when {
avatarType.isTombstoned -> TombstonedRoomAvatar(
size = avatarData.size,
avatarType = avatarType,
modifier = modifier,
contentDescription = contentDescription,
)
avatarData.url.isNullOrBlank() || hideAvatarImage -> InitialLetterAvatar(
avatarData = avatarData,
avatarType = avatarType,
modifier = modifier,
contentDescription = contentDescription,
forcedAvatarSize = null,
)
else -> ImageAvatar(
avatarData = avatarData,
avatarType = avatarType,
forcedAvatarSize = null,
modifier = modifier,
contentDescription = contentDescription,
)
}
}
@Preview(group = PreviewGroup.Avatars)
@Composable
internal fun SpaceAvatarPreview() =
ElementThemedPreview(
drawableFallbackForImages = CommonDrawables.sample_avatar,
) {
Row(
modifier = Modifier.padding(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
SpaceAvatar(
avatarData = anAvatarData(),
avatarType = AvatarType.Space(cornerSize = 16.dp),
)
SpaceAvatar(
avatarData = anAvatarData(),
avatarType = AvatarType.Space(
cornerSize = 16.dp,
isTombstoned = true,
),
)
}
}

View file

@ -8,9 +8,11 @@
package io.element.android.libraries.designsystem.components.avatar package io.element.android.libraries.designsystem.components.avatar
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -34,12 +36,13 @@ internal fun TextAvatar(
size: Dp, size: Dp,
colors: AvatarColors, colors: AvatarColors,
contentDescription: String?, contentDescription: String?,
avatarType: AvatarType,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Box( Box(
modifier modifier
.size(size) .size(size)
.clip(CircleShape) .clip(avatarType.avatarShape())
.background(color = colors.background) .background(color = colors.background)
) { ) {
val fontSize = size.toSp() / 2 val fontSize = size.toSp() / 2
@ -64,13 +67,25 @@ internal fun TextAvatar(
@Preview(group = PreviewGroup.Avatars) @Preview(group = PreviewGroup.Avatars)
@Composable @Composable
internal fun TextAvatarPreview() = ElementPreview { internal fun TextAvatarPreview() = ElementPreview {
TextAvatar( Row(
text = "AB", modifier = Modifier.padding(8.dp),
size = 40.dp, horizontalArrangement = Arrangement.spacedBy(8.dp),
colors = AvatarColors( ) {
background = ElementTheme.colors.bgSubtlePrimary, listOf(
foreground = ElementTheme.colors.iconPrimary, AvatarType.User,
), AvatarType.Room(),
contentDescription = null, AvatarType.Space(8.dp),
) ).forEach { avatarType ->
TextAvatar(
text = "AB",
size = 40.dp,
colors = AvatarColors(
background = ElementTheme.colors.bgSubtlePrimary,
foreground = ElementTheme.colors.iconPrimary,
),
avatarType = avatarType,
contentDescription = null,
)
}
} }
}

View file

@ -16,8 +16,9 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup import io.element.android.libraries.designsystem.preview.PreviewGroup
@Composable @Composable
fun TombstonedRoomAvatar( internal fun TombstonedRoomAvatar(
size: AvatarSize, size: AvatarSize,
avatarType: AvatarType,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
contentDescription: String? = null, contentDescription: String? = null,
) { ) {
@ -29,7 +30,8 @@ fun TombstonedRoomAvatar(
foreground = ElementTheme.colors.iconTertiary foreground = ElementTheme.colors.iconTertiary
), ),
modifier = modifier, modifier = modifier,
contentDescription = contentDescription avatarType = avatarType,
contentDescription = contentDescription,
) )
} }
@ -38,6 +40,7 @@ fun TombstonedRoomAvatar(
internal fun TombstonedRoomAvatarPreview() = ElementPreview { internal fun TombstonedRoomAvatarPreview() = ElementPreview {
TombstonedRoomAvatar( TombstonedRoomAvatar(
size = AvatarSize.RoomListItem, size = AvatarSize.RoomListItem,
avatarType = AvatarType.Room(),
contentDescription = null, contentDescription = null,
) )
} }

View file

@ -35,6 +35,7 @@ import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.libraries.designsystem.components.avatar.Avatar import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
@ -49,6 +50,7 @@ fun EditableAvatarView(
displayName: String?, displayName: String?,
avatarUrl: Uri?, avatarUrl: Uri?,
avatarSize: AvatarSize, avatarSize: AvatarSize,
avatarType: AvatarType,
onAvatarClick: () -> Unit, onAvatarClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@ -74,12 +76,14 @@ fun EditableAvatarView(
null, "mxc" -> { null, "mxc" -> {
Avatar( Avatar(
avatarData = AvatarData(matrixId, displayName, avatarUrl?.toString(), size = avatarSize), avatarData = AvatarData(matrixId, displayName, avatarUrl?.toString(), size = avatarSize),
avatarType = avatarType,
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
) )
} }
else -> { else -> {
UnsavedAvatar( UnsavedAvatar(
avatarUri = avatarUrl, avatarUri = avatarUrl,
avatarType = avatarType,
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
) )
} }
@ -116,6 +120,7 @@ internal fun EditableAvatarViewPreview(
displayName = "A room", displayName = "A room",
avatarUrl = uri, avatarUrl = uri,
avatarSize = AvatarSize.EditRoomDetails, avatarSize = AvatarSize.EditRoomDetails,
avatarType = AvatarType.User,
onAvatarClick = {}, onAvatarClick = {},
) )
} }

View file

@ -28,8 +28,9 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.avatar.RoomAvatar import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
@ -53,10 +54,12 @@ fun SelectedRoom(
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
RoomAvatar( Avatar(
avatarData = roomInfo.getAvatarData(AvatarSize.SelectedRoom), avatarData = roomInfo.getAvatarData(AvatarSize.SelectedRoom),
heroes = roomInfo.heroes.map { it.getAvatarData(AvatarSize.SelectedRoom) }.toImmutableList(), avatarType = AvatarType.Room(
isTombstoned = roomInfo.isTombstoned, heroes = roomInfo.heroes.map { it.getAvatarData(AvatarSize.SelectedRoom) }.toImmutableList(),
isTombstoned = roomInfo.isTombstoned,
),
) )
Text( Text(
// If name is null, we do not have space to render "No room name", so just use `#` here. // If name is null, we do not have space to render "No room name", so just use `#` here.

View file

@ -9,10 +9,11 @@ package io.element.android.libraries.matrix.ui.components
import android.net.Uri import android.net.Uri
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.AddAPhoto import androidx.compose.material.icons.outlined.AddAPhoto
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@ -27,6 +28,8 @@ import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage import coil3.compose.AsyncImage
import coil3.request.ImageRequest import coil3.request.ImageRequest
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.components.avatar.avatarShape
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
@ -40,11 +43,12 @@ import io.element.android.libraries.designsystem.theme.temporaryColorBgSpecial
@Composable @Composable
fun UnsavedAvatar( fun UnsavedAvatar(
avatarUri: Uri?, avatarUri: Uri?,
avatarType: AvatarType,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val commonModifier = modifier val commonModifier = modifier
.size(70.dp) .size(70.dp)
.clip(CircleShape) .clip(avatarType.avatarShape())
if (avatarUri != null) { if (avatarUri != null) {
val context = LocalContext.current val context = LocalContext.current
@ -75,8 +79,13 @@ fun UnsavedAvatar(
@PreviewsDayNight @PreviewsDayNight
@Composable @Composable
internal fun UnsavedAvatarPreview() = ElementPreview { internal fun UnsavedAvatarPreview() = ElementPreview {
Row { Row(
UnsavedAvatar(null) modifier = Modifier.padding(8.dp),
UnsavedAvatar(Uri.EMPTY) horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
UnsavedAvatar(null, AvatarType.User)
UnsavedAvatar(Uri.EMPTY, AvatarType.User)
UnsavedAvatar(null, AvatarType.Space(8.dp))
UnsavedAvatar(Uri.EMPTY, AvatarType.Space(8.dp))
} }
} }

View file

@ -32,8 +32,9 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.avatar.RoomAvatar import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@ -214,12 +215,14 @@ private fun RoomSummaryView(
.heightIn(56.dp), .heightIn(56.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
RoomAvatar( Avatar(
avatarData = roomInfo.getAvatarData(size = AvatarSize.RoomSelectRoomListItem), avatarData = roomInfo.getAvatarData(size = AvatarSize.RoomSelectRoomListItem),
heroes = roomInfo.heroes.map { user -> avatarType = AvatarType.Room(
user.getAvatarData(size = AvatarSize.RoomSelectRoomListItem) heroes = roomInfo.heroes.map { user ->
}.toPersistentList(), user.getAvatarData(size = AvatarSize.RoomSelectRoomListItem)
isTombstoned = roomInfo.isTombstoned, }.toPersistentList(),
isTombstoned = roomInfo.isTombstoned,
),
) )
Column( Column(
modifier = Modifier modifier = Modifier

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d61143149a23cbb1549ee11b1ad00fd4eee16d173407bc847bde91c39cd1b5bc
size 9178

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:0645d454bcaac9e38fe9b6400347ee0fc92a71ef531f72b9ec527f644e050862 oid sha256:0b632082558328aa485712b8684016a84a9d1eaba7f96cd92b47d364e6c9169f
size 5488 size 7981

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:2f238177f5bf6e2964aa7f1d661af45c9bf09507d1a7b34dc749603e69056af1 oid sha256:e20e9a7264a6784fbaf6525e73a07318abd27bcf025541b880fd27ac0cca4ba4
size 36330 size 69466

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:1ec7b0c98849e856978f3f5601680fa9a72597340aeca40fb03e5c232c3d651f oid sha256:991318dc36c1e6b86a753241638c36adafb896f852f4d5d0e15dd251fa025311
size 36002 size 68974