Introduce AvatarType to be able to render space avatars
This commit is contained in:
parent
d524c23b8d
commit
8df920a3ac
22 changed files with 337 additions and 78 deletions
|
|
@ -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),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -109,7 +115,12 @@ private fun SuggestionItemView(
|
||||||
is ResolvedSuggestion.Alias -> suggestion.roomAlias.value
|
is ResolvedSuggestion.Alias -> suggestion.roomAlias.value
|
||||||
}
|
}
|
||||||
|
|
||||||
Avatar(avatarData = avatarData, modifier = Modifier.padding(start = 16.dp, top = 12.dp, bottom = 12.dp))
|
Avatar(
|
||||||
|
avatarData = avatarData,
|
||||||
|
avatarType = avatarType,
|
||||||
|
modifier = Modifier.padding(start = 16.dp, top = 12.dp, bottom = 12.dp),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
|
||||||
|
|
@ -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 = {
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ 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.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.SideEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
|
@ -37,15 +36,50 @@ import timber.log.Timber
|
||||||
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 +87,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,
|
||||||
|
|
@ -61,8 +96,9 @@ fun Avatar(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ImageAvatar(
|
internal fun ImageAvatar(
|
||||||
avatarData: AvatarData,
|
avatarData: AvatarData,
|
||||||
|
avatarType: AvatarType,
|
||||||
forcedAvatarSize: Dp?,
|
forcedAvatarSize: Dp?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
contentDescription: String? = null,
|
contentDescription: String? = null,
|
||||||
|
|
@ -74,7 +110,7 @@ private fun ImageAvatar(
|
||||||
contentScale = ContentScale.Crop,
|
contentScale = ContentScale.Crop,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.size(size)
|
.size(size)
|
||||||
.clip(CircleShape)
|
.clip(avatarShape(avatarType))
|
||||||
) {
|
) {
|
||||||
val collectedState by painter.state.collectAsState()
|
val collectedState by painter.state.collectAsState()
|
||||||
when (val state = collectedState) {
|
when (val state = collectedState) {
|
||||||
|
|
@ -85,12 +121,14 @@ private fun ImageAvatar(
|
||||||
}
|
}
|
||||||
InitialLetterAvatar(
|
InitialLetterAvatar(
|
||||||
avatarData = avatarData,
|
avatarData = avatarData,
|
||||||
|
avatarType = avatarType,
|
||||||
forcedAvatarSize = forcedAvatarSize,
|
forcedAvatarSize = forcedAvatarSize,
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> InitialLetterAvatar(
|
else -> InitialLetterAvatar(
|
||||||
avatarData = avatarData,
|
avatarData = avatarData,
|
||||||
|
avatarType = avatarType,
|
||||||
forcedAvatarSize = forcedAvatarSize,
|
forcedAvatarSize = forcedAvatarSize,
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
)
|
)
|
||||||
|
|
@ -99,8 +137,9 @@ private fun ImageAvatar(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun InitialLetterAvatar(
|
internal fun InitialLetterAvatar(
|
||||||
avatarData: AvatarData,
|
avatarData: AvatarData,
|
||||||
|
avatarType: AvatarType,
|
||||||
forcedAvatarSize: Dp?,
|
forcedAvatarSize: Dp?,
|
||||||
contentDescription: String?,
|
contentDescription: String?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
|
@ -109,6 +148,7 @@ private fun InitialLetterAvatar(
|
||||||
TextAvatar(
|
TextAvatar(
|
||||||
text = avatarData.initialLetter,
|
text = avatarData.initialLetter,
|
||||||
size = forcedAvatarSize ?: avatarData.size.dp,
|
size = forcedAvatarSize ?: avatarData.size.dp,
|
||||||
|
avatarType = avatarType,
|
||||||
colors = avatarColors,
|
colors = avatarColors,
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* 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 avatarShape(
|
||||||
|
avatarType: AvatarType,
|
||||||
|
): Shape {
|
||||||
|
return when (avatarType) {
|
||||||
|
is AvatarType.Space -> RoundedCornerShape(avatarType.cornerSize)
|
||||||
|
is AvatarType.Room,
|
||||||
|
AvatarType.User -> CircleShape
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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.ui.unit.Dp
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
|
||||||
|
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,
|
||||||
|
) : AvatarType
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* 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,
|
||||||
|
isTombstoned: Boolean = false,
|
||||||
|
hideAvatarImage: Boolean = false,
|
||||||
|
contentDescription: String? = null,
|
||||||
|
) {
|
||||||
|
when {
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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(avatarShape(avatarType))
|
||||||
.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,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,10 @@ 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,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
avatarType: AvatarType,
|
||||||
contentDescription: String? = null,
|
contentDescription: String? = null,
|
||||||
) {
|
) {
|
||||||
TextAvatar(
|
TextAvatar(
|
||||||
|
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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.avatarShape
|
||||||
|
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
|
||||||
|
|
@ -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(avatarShape(avatarType))
|
||||||
|
|
||||||
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue