Add space header.

This commit is contained in:
Benoit Marty 2025-09-01 21:33:55 +02:00 committed by Benoit Marty
parent a0ec8658af
commit a22ab5e663
9 changed files with 152 additions and 31 deletions

View file

@ -43,6 +43,7 @@ class HomeSpacesPresenter @Inject constructor(
}
return HomeSpacesState(
space = CurrentSpace.Root,
spaceRooms = spaceRooms,
seenSpaceInvites = seenSpaceInvites,
hideInvitesAvatar = hideInvitesAvatar,

View file

@ -12,8 +12,14 @@ import io.element.android.libraries.matrix.api.spaces.SpaceRoom
import kotlinx.collections.immutable.ImmutableSet
data class HomeSpacesState(
val space: CurrentSpace,
val spaceRooms: List<SpaceRoom>,
val seenSpaceInvites: ImmutableSet<SpaceId>,
val hideInvitesAvatar: Boolean,
val eventSink: (HomeSpacesEvents) -> Unit,
)
sealed interface CurrentSpace {
object Root : CurrentSpace
data class Space(val spaceRoom: SpaceRoom) : CurrentSpace
}

View file

@ -19,17 +19,25 @@ open class HomeSpacesStateProvider : PreviewParameterProvider<HomeSpacesState> {
spaceRooms = SpaceRoomProvider().values.toList(),
seenSpaceInvites = setOf(
SpaceId("!spaceId3:example.com"),
).toImmutableSet(),
)
),
),
aHomeSpacesState(
space = CurrentSpace.Space(
spaceRoom = aSpaceRooms(spaceId = SpaceId("!mySpace:example.com"))
),
spaceRooms = aListOfSpaceRooms(),
),
)
}
internal fun aHomeSpacesState(
space: CurrentSpace = CurrentSpace.Root,
spaceRooms: List<SpaceRoom> = aListOfSpaceRooms(),
seenSpaceInvites: Set<SpaceId> = emptySet(),
hideInvitesAvatar: Boolean = false,
eventSink: (HomeSpacesEvents) -> Unit = {},
) = HomeSpacesState(
space = space,
spaceRooms = spaceRooms,
seenSpaceInvites = seenSpaceInvites.toImmutableSet(),
hideInvitesAvatar = hideInvitesAvatar,
@ -38,8 +46,8 @@ internal fun aHomeSpacesState(
fun aListOfSpaceRooms(): List<SpaceRoom> {
return listOf(
aSpaceRooms(),
aSpaceRooms(),
aSpaceRooms(),
aSpaceRooms(spaceId = SpaceId("!spaceId0:example.com")),
aSpaceRooms(spaceId = SpaceId("!spaceId1:example.com")),
aSpaceRooms(spaceId = SpaceId("!spaceId2:example.com")),
)
}

View file

@ -11,10 +11,15 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.matrix.api.core.SpaceId
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.ui.components.SpaceHeaderRootView
import io.element.android.libraries.matrix.ui.components.SpaceHeaderView
import io.element.android.libraries.matrix.ui.model.getAvatarData
import kotlinx.collections.immutable.toImmutableList
@Composable
fun HomeSpacesView(
@ -23,6 +28,29 @@ fun HomeSpacesView(
modifier: Modifier = Modifier,
) {
LazyColumn(modifier) {
val space = state.space
when (space) {
CurrentSpace.Root -> {
item {
SpaceHeaderRootView(
numberOfSpaces = state.spaceRooms.size,
// TODO
numberOfRooms = 0,
)
}
}
is CurrentSpace.Space -> item {
SpaceHeaderView(
avatarData = space.spaceRoom.getAvatarData(AvatarSize.SpaceHeader),
name = space.spaceRoom.name,
topic = space.spaceRoom.topic,
joinRule = space.spaceRoom.joinRule,
heroes = space.spaceRoom.heroes.toImmutableList(),
numberOfMembers = space.spaceRoom.numJoinedMembers,
numberOfRooms = space.spaceRoom.childrenCount,
)
}
}
state.spaceRooms.forEach {
item(it.spaceId) {
val isInvitation = it.state == CurrentUserMembership.INVITED

View file

@ -546,7 +546,7 @@ private fun DefaultLoadedContent(
},
memberCount = {
if (contentState.showMemberCount) {
MembersCountMolecule(memberCount = contentState.numberOfMembers ?: 0)
MembersCountMolecule(memberCount = contentState.numberOfMembers?.toInt() ?: 0)
}
}
)

View file

@ -26,7 +26,7 @@ import io.element.android.libraries.designsystem.theme.components.Text
@Composable
fun MembersCountMolecule(
memberCount: Long,
memberCount: Int,
modifier: Modifier = Modifier,
) {
Row(

View file

@ -0,0 +1,73 @@
/*
* 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.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.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.ui.strings.CommonStrings
/**
* Ref: https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=3643-2048
*/
@Composable
fun SpaceHeaderRootView(
numberOfSpaces: Int,
numberOfRooms: Int,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxWidth()
.padding(top = 32.dp, bottom = 24.dp, start = 16.dp, end = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
BigIcon(
style = BigIcon.Style.Default(CompoundIcons.WorkspaceSolid())
)
Text(
text = stringResource(CommonStrings.screen_space_list_title),
style = ElementTheme.typography.fontHeadingLgBold,
color = ElementTheme.colors.textPrimary,
textAlign = TextAlign.Center,
)
SpaceInfoRow(
leftText = numberOfSpaces(numberOfSpaces),
rightText = numberOfRooms(numberOfRooms),
)
Text(
text = stringResource(CommonStrings.screen_space_list_description),
style = ElementTheme.typography.fontBodyMdRegular,
color = ElementTheme.colors.textPrimary,
textAlign = TextAlign.Center,
)
}
}
@PreviewsDayNight
@Composable
internal fun SpaceHeaderRootViewPreview() = ElementPreview {
SpaceHeaderRootView(
numberOfSpaces = 3,
numberOfRooms = 10,
)
}

View file

@ -38,11 +38,11 @@ import kotlinx.collections.immutable.persistentListOf
@Composable
fun SpaceHeaderView(
avatarData: AvatarData,
name: String,
topic: String,
joinRule: JoinRule,
name: String?,
topic: String?,
joinRule: JoinRule?,
heroes: ImmutableList<MatrixUser>,
numberOfMembers: Long,
numberOfMembers: Int,
numberOfRooms: Int,
modifier: Modifier = Modifier,
topicMaxLines: Int = Int.MAX_VALUE,
@ -58,29 +58,34 @@ fun SpaceHeaderView(
avatarData = avatarData,
avatarType = AvatarType.Space(false),
)
Text(
text = name,
style = ElementTheme.typography.fontHeadingLgBold,
color = ElementTheme.colors.textPrimary,
textAlign = TextAlign.Center,
)
SpaceInfoRow(
joinRule = joinRule,
numberOfRooms = numberOfRooms,
)
name?.let {
Text(
text = name,
style = ElementTheme.typography.fontHeadingLgBold,
color = ElementTheme.colors.textPrimary,
textAlign = TextAlign.Center,
)
}
if (joinRule != null)
SpaceInfoRow(
joinRule = joinRule,
numberOfRooms = numberOfRooms,
)
SpaceMembersView(
heroes = heroes,
numberOfMembers = numberOfMembers,
modifier = Modifier.padding(horizontal = 32.dp),
)
Text(
text = topic,
style = ElementTheme.typography.fontBodyMdRegular,
color = ElementTheme.colors.textPrimary,
textAlign = TextAlign.Center,
maxLines = topicMaxLines,
overflow = TextOverflow.Ellipsis,
)
topic?.let {
Text(
text = topic,
style = ElementTheme.typography.fontBodyMdRegular,
color = ElementTheme.colors.textPrimary,
textAlign = TextAlign.Center,
maxLines = topicMaxLines,
overflow = TextOverflow.Ellipsis,
)
}
}
}

View file

@ -35,7 +35,7 @@ import kotlinx.collections.immutable.toImmutableList
@Composable
fun SpaceMembersView(
heroes: ImmutableList<MatrixUser>,
numberOfMembers: Long,
numberOfMembers: Int,
modifier: Modifier = Modifier,
) {
if (heroes.isEmpty()) {
@ -60,7 +60,7 @@ fun SpaceMembersView(
@Composable
private fun SpaceMembersWithAvatar(
heroes: ImmutableList<AvatarData>,
numberOfMembers: Long,
numberOfMembers: Int,
modifier: Modifier = Modifier,
) {
Row(