design (join room) : update design of join room screen

This commit is contained in:
ganfra 2025-09-16 14:51:02 +02:00
parent f675c95740
commit 9b2a1a711d
12 changed files with 198 additions and 148 deletions

View file

@ -101,7 +101,6 @@ sealed interface ContentState {
sealed interface JoinAuthorisationStatus { sealed interface JoinAuthorisationStatus {
data object None : JoinAuthorisationStatus data object None : JoinAuthorisationStatus
data class IsSpace(val applicationName: String) : JoinAuthorisationStatus
data class IsInvited(val inviteData: InviteData, val inviteSender: InviteSender?) : JoinAuthorisationStatus data class IsInvited(val inviteData: InviteData, val inviteSender: InviteSender?) : JoinAuthorisationStatus
data class IsBanned(val banSender: InviteSender?, val reason: String?) : JoinAuthorisationStatus data class IsBanned(val banSender: InviteSender?, val reason: String?) : JoinAuthorisationStatus
data object IsKnocked : JoinAuthorisationStatus data object IsKnocked : JoinAuthorisationStatus

View file

@ -7,21 +7,20 @@
package io.element.android.features.joinroom.impl package io.element.android.features.joinroom.impl
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@ -38,6 +37,7 @@ 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.compound.tokens.generated.CompoundIcons
import io.element.android.features.invite.api.InviteData import io.element.android.features.invite.api.InviteData
import io.element.android.libraries.designsystem.atomic.atoms.PlaceholderAtom import io.element.android.libraries.designsystem.atomic.atoms.PlaceholderAtom
import io.element.android.libraries.designsystem.atomic.atoms.RoomPreviewDescriptionAtom import io.element.android.libraries.designsystem.atomic.atoms.RoomPreviewDescriptionAtom
@ -65,14 +65,21 @@ 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
import io.element.android.libraries.designsystem.theme.components.ButtonSize import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconSource
import io.element.android.libraries.designsystem.theme.components.OutlinedButton import io.element.android.libraries.designsystem.theme.components.OutlinedButton
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.designsystem.theme.components.TextField import io.element.android.libraries.designsystem.theme.components.TextField
import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.designsystem.theme.placeholderBackground
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.ui.components.InviteSenderView import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.ui.components.SpaceInfoRow
import io.element.android.libraries.matrix.ui.components.SpaceMembersView
import io.element.android.libraries.matrix.ui.model.InviteSender
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.persistentListOf
@Composable @Composable
fun JoinRoomView( fun JoinRoomView(
@ -92,7 +99,7 @@ fun JoinRoomView(
containerColor = Color.Transparent, containerColor = Color.Transparent,
contentPadding = PaddingValues( contentPadding = PaddingValues(
horizontal = 16.dp, horizontal = 16.dp,
vertical = 32.dp vertical = 24.dp
), ),
topBar = { topBar = {
JoinRoomTopBar( JoinRoomTopBar(
@ -220,12 +227,14 @@ private fun JoinRoomFooter(
onClick = { onDeclineInvite(joinAuthorisationStatus.inviteData, false) }, onClick = { onDeclineInvite(joinAuthorisationStatus.inviteData, false) },
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
size = ButtonSize.LargeLowPadding, size = ButtonSize.LargeLowPadding,
leadingIcon = IconSource.Vector(CompoundIcons.Close())
) )
Button( Button(
text = stringResource(CommonStrings.action_accept), text = stringResource(CommonStrings.action_accept),
onClick = { onAcceptInvite(joinAuthorisationStatus.inviteData) }, onClick = { onAcceptInvite(joinAuthorisationStatus.inviteData) },
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
size = ButtonSize.LargeLowPadding, size = ButtonSize.LargeLowPadding,
leadingIcon = IconSource.Vector(CompoundIcons.Check())
) )
} }
Spacer(modifier = Modifier.height(24.dp)) Spacer(modifier = Modifier.height(24.dp))
@ -278,7 +287,6 @@ private fun JoinRoomFooter(
JoinAuthorisationStatus.Unknown -> JoinRestrictedFooter(onJoinRoom) JoinAuthorisationStatus.Unknown -> JoinRestrictedFooter(onJoinRoom)
JoinAuthorisationStatus.Restricted -> JoinRestrictedFooter(onJoinRoom) JoinAuthorisationStatus.Restricted -> JoinRestrictedFooter(onJoinRoom)
JoinAuthorisationStatus.Unauthorized -> JoinUnauthorizedFooter(onGoBack) JoinAuthorisationStatus.Unauthorized -> JoinUnauthorizedFooter(onGoBack)
is JoinAuthorisationStatus.IsSpace -> UnsupportedSpaceFooter(joinAuthorisationStatus.applicationName, onGoBack)
JoinAuthorisationStatus.None -> Unit JoinAuthorisationStatus.None -> Unit
} }
} }
@ -397,19 +405,40 @@ private fun JoinRoomContent(
IsKnockedLoadedContent() IsKnockedLoadedContent()
} }
else -> { else -> {
Column(horizontalAlignment = Alignment.CenterHorizontally) { Column(
val inviteSender = (contentState.joinAuthorisationStatus as? JoinAuthorisationStatus.IsInvited)?.inviteSender horizontalAlignment = Alignment.CenterHorizontally,
if (inviteSender != null) { modifier = Modifier.verticalScroll(rememberScrollState())
InviteSenderView(inviteSender = inviteSender, hideAvatarImage = hideAvatarsImages) ) {
Spacer(modifier = Modifier.height(32.dp))
}
DefaultLoadedContent( DefaultLoadedContent(
modifier = Modifier.verticalScroll(rememberScrollState()),
contentState = contentState, contentState = contentState,
knockMessage = knockMessage,
hideAvatarImage = hideAvatarsImages, hideAvatarImage = hideAvatarsImages,
onKnockMessageUpdate = onKnockMessageUpdate
) )
when (contentState.joinAuthorisationStatus) {
is JoinAuthorisationStatus.IsInvited -> {
val inviteSender = contentState.joinAuthorisationStatus.inviteSender
if (inviteSender != null) {
Spacer(Modifier.height(16.dp))
InvitedByView(inviteSender, hideAvatarsImages)
}
}
is JoinAuthorisationStatus.CanKnock -> {
Spacer(modifier = Modifier.height(24.dp))
val supportingText = if (knockMessage.isNotEmpty()) {
"${knockMessage.length}/$MAX_KNOCK_MESSAGE_LENGTH"
} else {
stringResource(R.string.screen_join_room_knock_message_description)
}
TextField(
value = knockMessage,
onValueChange = onKnockMessageUpdate,
maxLines = 3,
minLines = 3,
modifier = Modifier.fillMaxWidth(),
supportingText = supportingText
)
}
else -> Unit
}
} }
} }
} }
@ -422,6 +451,45 @@ private fun JoinRoomContent(
} }
} }
@Composable
private fun InvitedByView(
sender: InviteSender,
hideAvatarImage: Boolean,
modifier: Modifier = Modifier
) {
Column(
modifier
.fillMaxWidth()
.padding(vertical = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Invited by",
style = ElementTheme.typography.fontBodyMdRegular,
color = ElementTheme.colors.textSecondary
)
Spacer(Modifier.height(8.dp))
Avatar(
avatarData = sender.avatarData,
avatarType = AvatarType.User,
hideImage = hideAvatarImage,
forcedAvatarSize = AvatarSize.RoomPreviewInviter.dp
)
Spacer(Modifier.height(8.dp))
Text(
text = sender.displayName,
style = ElementTheme.typography.fontBodyLgRegular,
color = ElementTheme.colors.textPrimary
)
Spacer(Modifier.height(4.dp))
Text(
text = sender.userId.value,
style = ElementTheme.typography.fontBodySmRegular,
color = ElementTheme.colors.textSecondary
)
}
}
@Composable @Composable
private fun UnknownRoomContent( private fun UnknownRoomContent(
modifier: Modifier = Modifier modifier: Modifier = Modifier
@ -429,7 +497,21 @@ private fun UnknownRoomContent(
RoomPreviewOrganism( RoomPreviewOrganism(
modifier = modifier, modifier = modifier,
avatar = { avatar = {
Spacer(modifier = Modifier.size(AvatarSize.RoomHeader.dp)) Box(
modifier = modifier
.size(AvatarSize.RoomPreviewHeader.dp)
.background(
color = ElementTheme.colors.placeholderBackground,
shape = CircleShape
)
) {
Icon(
modifier = Modifier.align(Alignment.Center),
tint = ElementTheme.colors.iconPrimary,
imageVector = CompoundIcons.VisibilityOff(),
contentDescription = null,
)
}
}, },
title = { title = {
RoomPreviewTitleAtom(stringResource(R.string.screen_join_room_title_no_preview)) RoomPreviewTitleAtom(stringResource(R.string.screen_join_room_title_no_preview))
@ -448,7 +530,7 @@ private fun IncompleteContent(
RoomPreviewOrganism( RoomPreviewOrganism(
modifier = modifier, modifier = modifier,
avatar = { avatar = {
PlaceholderAtom(width = AvatarSize.RoomHeader.dp, height = AvatarSize.RoomHeader.dp) PlaceholderAtom(width = AvatarSize.RoomPreviewHeader.dp, height = AvatarSize.RoomPreviewHeader.dp)
}, },
title = { title = {
when (roomIdOrAlias) { when (roomIdOrAlias) {
@ -471,43 +553,32 @@ private fun IncompleteContent(
@Composable @Composable
private fun IsKnockedLoadedContent(modifier: Modifier = Modifier) { private fun IsKnockedLoadedContent(modifier: Modifier = Modifier) {
BoxWithConstraints( IconTitleSubtitleMolecule(
modifier = modifier modifier = modifier.padding(horizontal = 8.dp),
.fillMaxHeight() iconStyle = BigIcon.Style.SuccessSolid,
.padding(horizontal = 16.dp), title = stringResource(R.string.screen_join_room_knock_sent_title),
contentAlignment = Alignment.Center, subTitle = stringResource(R.string.screen_join_room_knock_sent_description),
) { )
IconTitleSubtitleMolecule(
modifier = Modifier.sizeIn(minHeight = maxHeight * 0.7f),
iconStyle = BigIcon.Style.SuccessSolid,
title = stringResource(R.string.screen_join_room_knock_sent_title),
subTitle = stringResource(R.string.screen_join_room_knock_sent_description),
)
}
} }
@Composable @Composable
private fun DefaultLoadedContent( private fun DefaultLoadedContent(
contentState: ContentState.Loaded, contentState: ContentState.Loaded,
knockMessage: String,
hideAvatarImage: Boolean, hideAvatarImage: Boolean,
onKnockMessageUpdate: (String) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
RoomPreviewOrganism( RoomPreviewOrganism(
modifier = modifier, modifier = modifier,
avatar = { avatar = {
Avatar( Avatar(
contentState.avatarData(AvatarSize.RoomHeader), contentState.avatarData(AvatarSize.RoomPreviewHeader),
hideImage = hideAvatarImage, hideImage = hideAvatarImage,
avatarType = AvatarType.Room(), avatarType = if (contentState.isSpace) AvatarType.Space() else AvatarType.Room(),
) )
}, },
title = { title = {
if (contentState.name != null) { if (contentState.name != null) {
RoomPreviewTitleAtom( RoomPreviewTitleAtom(title = contentState.name)
title = contentState.name,
)
} else { } else {
RoomPreviewTitleAtom( RoomPreviewTitleAtom(
title = stringResource(id = CommonStrings.common_no_room_name), title = stringResource(id = CommonStrings.common_no_room_name),
@ -516,37 +587,32 @@ private fun DefaultLoadedContent(
} }
}, },
subtitle = { subtitle = {
if (contentState.alias != null) { when {
RoomPreviewSubtitleAtom(contentState.alias.value) contentState.isSpace -> {
} SpaceInfoRow(
}, joinRule = contentState.joinRule ?: JoinRule.Public,
description = { numberOfRooms = contentState.childrenCount ?: 0,
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
RoomPreviewDescriptionAtom(contentState.topic ?: "")
if (contentState.joinAuthorisationStatus is JoinAuthorisationStatus.CanKnock) {
Spacer(modifier = Modifier.height(24.dp))
val supportingText = if (knockMessage.isNotEmpty()) {
"${knockMessage.length}/$MAX_KNOCK_MESSAGE_LENGTH"
} else {
stringResource(R.string.screen_join_room_knock_message_description)
}
TextField(
value = knockMessage,
onValueChange = onKnockMessageUpdate,
maxLines = 3,
minLines = 3,
modifier = Modifier.fillMaxWidth(),
supportingText = supportingText
) )
} }
contentState.alias != null -> {
RoomPreviewSubtitleAtom(contentState.alias.value)
}
} }
}, },
description = {
RoomPreviewDescriptionAtom(
contentState.topic ?: "",
maxLines = if (contentState.joinAuthorisationStatus is JoinAuthorisationStatus.CanJoin) Int.MAX_VALUE else 2
)
},
memberCount = { memberCount = {
if (contentState.showMemberCount) { if (contentState.showMemberCount) {
MembersCountMolecule(memberCount = contentState.numberOfMembers?.toInt() ?: 0) val membersCount = contentState.numberOfMembers?.toInt() ?: 0
if (contentState.isSpace) {
SpaceMembersView(persistentListOf(), membersCount)
} else {
MembersCountMolecule(memberCount = membersCount)
}
} }
} }
) )

View file

@ -655,7 +655,10 @@ class JoinRoomPresenterTest {
isDm = false, isDm = false,
roomType = RoomType.Room, roomType = RoomType.Room,
roomAvatarUrl = "avatarUrl", roomAvatarUrl = "avatarUrl",
joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin,
joinRule = JoinRule.Public,
childrenCount = null,
heroes = persistentListOf()
) )
) )
} }
@ -724,7 +727,10 @@ class JoinRoomPresenterTest {
), ),
membershipChangeReason = null, membershipChangeReason = null,
), ),
) ),
joinRule = JoinRule.Public,
childrenCount = null,
heroes = persistentListOf()
) )
) )
} }
@ -789,7 +795,10 @@ class JoinRoomPresenterTest {
membershipChangeReason = null, membershipChangeReason = null,
), ),
reason = null, reason = null,
) ),
joinRule = JoinRule.Public,
childrenCount = null,
heroes = persistentListOf()
) )
) )
} }
@ -842,7 +851,10 @@ class JoinRoomPresenterTest {
isDm = false, isDm = false,
roomType = RoomType.Room, roomType = RoomType.Room,
roomAvatarUrl = "avatarUrl", roomAvatarUrl = "avatarUrl",
joinAuthorisationStatus = JoinAuthorisationStatus.IsKnocked joinAuthorisationStatus = JoinAuthorisationStatus.IsKnocked,
joinRule = JoinRule.Public,
childrenCount = null,
heroes = persistentListOf()
) )
) )
} }
@ -949,26 +961,6 @@ class JoinRoomPresenterTest {
} }
} }
@Test
fun `present - when room is not known RoomPreview is loaded as Space`() = runTest {
val client = FakeMatrixClient(
getNotJoinedRoomResult = { _, _ ->
Result.success(
aRoomPreview(info = aRoomPreviewInfo(isSpace = true))
)
}
)
val presenter = createJoinRoomPresenter(
matrixClient = client
)
presenter.test {
skipItems(1)
awaitItem().also { state ->
assertThat(state.joinAuthorisationStatus).isEqualTo(JoinAuthorisationStatus.UnsupportedSpace("AppName"))
}
}
}
@Test @Test
fun `present - when room is not known RoomPreview is loaded with error`() = runTest { fun `present - when room is not known RoomPreview is loaded with error`() = runTest {
val client = FakeMatrixClient( val client = FakeMatrixClient(

View file

@ -117,7 +117,7 @@ private fun RoomAliasResolverContent(
RoomPreviewOrganism( RoomPreviewOrganism(
modifier = modifier, modifier = modifier,
avatar = { avatar = {
PlaceholderAtom(width = AvatarSize.RoomHeader.dp, height = AvatarSize.RoomHeader.dp) PlaceholderAtom(width = AvatarSize.RoomPreviewHeader.dp, height = AvatarSize.RoomPreviewHeader.dp)
}, },
title = { title = {
RoomPreviewSubtitleAtom(roomAlias.value) RoomPreviewSubtitleAtom(roomAlias.value)

View file

@ -396,10 +396,10 @@ private fun RoomHeaderSection(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
Avatar( Avatar(
avatarData = AvatarData(roomId.value, roomName, avatarUrl, AvatarSize.RoomHeader), avatarData = AvatarData(roomId.value, roomName, avatarUrl, AvatarSize.RoomDetailsHeader),
avatarType = AvatarType.Room( avatarType = AvatarType.Room(
heroes = heroes.map { user -> heroes = heroes.map { user ->
user.getAvatarData(size = AvatarSize.RoomHeader) user.getAvatarData(size = AvatarSize.RoomDetailsHeader)
}.toPersistentList(), }.toPersistentList(),
isTombstoned = isTombstoned, isTombstoned = isTombstoned,
), ),

View file

@ -15,14 +15,18 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
@Composable @Composable
fun RoomPreviewDescriptionAtom(description: String, modifier: Modifier = Modifier) { fun RoomPreviewDescriptionAtom(
description: String,
modifier: Modifier = Modifier,
maxLines: Int = Int.MAX_VALUE,
) {
Text( Text(
modifier = modifier, modifier = modifier,
text = description, text = description,
style = ElementTheme.typography.fontBodySmRegular, style = ElementTheme.typography.fontBodyMdRegular,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
color = ElementTheme.colors.textSecondary, color = ElementTheme.colors.textPrimary,
maxLines = 3, maxLines = maxLines,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
) )
} }

View file

@ -18,7 +18,7 @@ fun RoomPreviewSubtitleAtom(subtitle: String, modifier: Modifier = Modifier) {
Text( Text(
modifier = modifier, modifier = modifier,
text = subtitle, text = subtitle,
style = ElementTheme.typography.fontBodyMdRegular, style = ElementTheme.typography.fontBodyLgRegular,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
color = ElementTheme.colors.textSecondary, color = ElementTheme.colors.textSecondary,
) )

View file

@ -23,7 +23,7 @@ fun RoomPreviewTitleAtom(
Text( Text(
modifier = modifier, modifier = modifier,
text = title, text = title,
style = ElementTheme.typography.fontHeadingMdBold, style = ElementTheme.typography.fontHeadingLgBold,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
fontStyle = fontStyle, fontStyle = fontStyle,
color = ElementTheme.colors.textPrimary, color = ElementTheme.colors.textPrimary,

View file

@ -34,14 +34,13 @@ fun RoomPreviewOrganism(
title() title()
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
subtitle() subtitle()
Spacer(modifier = Modifier.height(8.dp))
if (memberCount != null) { if (memberCount != null) {
Spacer(modifier = Modifier.height(8.dp))
memberCount() memberCount()
} }
Spacer(modifier = Modifier.height(8.dp))
if (description != null) { if (description != null) {
Spacer(modifier = Modifier.height(16.dp))
description() description()
} }
Spacer(modifier = Modifier.height(24.dp))
} }
} }

View file

@ -14,7 +14,7 @@ enum class AvatarSize(val dp: Dp) {
CurrentUserTopBar(32.dp), CurrentUserTopBar(32.dp),
IncomingCall(140.dp), IncomingCall(140.dp),
RoomHeader(96.dp), RoomDetailsHeader(96.dp),
RoomListItem(52.dp), RoomListItem(52.dp),
SpaceListItem(52.dp), SpaceListItem(52.dp),
@ -68,5 +68,7 @@ enum class AvatarSize(val dp: Dp) {
OrganizationHeader(64.dp), OrganizationHeader(64.dp),
SpaceHeader(64.dp), SpaceHeader(64.dp),
RoomPreviewHeader(64.dp),
RoomPreviewInviter(56.dp),
SpaceMember(24.dp), SpaceMember(24.dp),
} }

View file

@ -7,19 +7,14 @@
package io.element.android.libraries.matrix.ui.components package io.element.android.libraries.matrix.ui.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.datasource.LoremIpsum import androidx.compose.ui.tooling.preview.datasource.LoremIpsum
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme import io.element.android.libraries.designsystem.atomic.atoms.RoomPreviewDescriptionAtom
import io.element.android.libraries.designsystem.atomic.atoms.RoomPreviewTitleAtom
import io.element.android.libraries.designsystem.atomic.organisms.RoomPreviewOrganism
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
@ -47,47 +42,40 @@ fun SpaceHeaderView(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
topicMaxLines: Int = Int.MAX_VALUE, topicMaxLines: Int = Int.MAX_VALUE,
) { ) {
Column( RoomPreviewOrganism(
modifier = modifier modifier = modifier.padding(24.dp),
.fillMaxWidth() avatar = {
.padding(top = 32.dp, bottom = 24.dp, start = 16.dp, end = 16.dp), Avatar(
horizontalAlignment = Alignment.CenterHorizontally, avatarData = avatarData,
verticalArrangement = Arrangement.spacedBy(16.dp) avatarType = AvatarType.Space(),
) {
Avatar(
avatarData = avatarData,
avatarType = AvatarType.Space(false),
)
name?.let {
Text(
text = name,
style = ElementTheme.typography.fontHeadingLgBold,
color = ElementTheme.colors.textPrimary,
textAlign = TextAlign.Center,
) )
} },
if (joinRule != null) { title = {
SpaceInfoRow( name?.let {
joinRule = joinRule, RoomPreviewTitleAtom(title = name)
numberOfRooms = numberOfRooms, }
},
subtitle = {
if (joinRule != null) {
SpaceInfoRow(
joinRule = joinRule,
numberOfRooms = numberOfRooms,
)
}
},
description = if (topic != null) {
{ RoomPreviewDescriptionAtom(description = topic, maxLines = topicMaxLines) }
} else {
null
},
memberCount = {
SpaceMembersView(
heroes = heroes,
numberOfMembers = numberOfMembers,
modifier = Modifier.padding(horizontal = 32.dp),
) )
} },
SpaceMembersView( )
heroes = heroes,
numberOfMembers = numberOfMembers,
modifier = Modifier.padding(horizontal = 32.dp),
)
topic?.let {
Text(
text = topic,
style = ElementTheme.typography.fontBodyMdRegular,
color = ElementTheme.colors.textPrimary,
textAlign = TextAlign.Center,
maxLines = topicMaxLines,
overflow = TextOverflow.Ellipsis,
)
}
}
} }
@PreviewsDayNight @PreviewsDayNight

View file

@ -105,7 +105,7 @@ class DefaultNotificationConversationService(
targetSize = defaultShortcutIconSize.toLong() targetSize = defaultShortcutIconSize.toLong()
)?.let(IconCompat::createWithBitmap) )?.let(IconCompat::createWithBitmap)
?: InitialsAvatarBitmapGenerator(useDarkTheme = useDarkTheme) ?: InitialsAvatarBitmapGenerator(useDarkTheme = useDarkTheme)
.generateBitmap(defaultShortcutIconSize, AvatarData(id = roomId.value, name = roomName, size = AvatarSize.RoomHeader)) .generateBitmap(defaultShortcutIconSize, AvatarData(id = roomId.value, name = roomName, size = AvatarSize.RoomDetailsHeader))
?.let(IconCompat::createWithAdaptiveBitmap) ?.let(IconCompat::createWithAdaptiveBitmap)
val shortcutInfo = ShortcutInfoCompat.Builder(context, createShortcutId(sessionId, roomId)) val shortcutInfo = ShortcutInfoCompat.Builder(context, createShortcutId(sessionId, roomId))