Add space header.
This commit is contained in:
parent
cbcf86b1c9
commit
fdea38ddb0
9 changed files with 152 additions and 31 deletions
|
|
@ -43,6 +43,7 @@ class HomeSpacesPresenter @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
return HomeSpacesState(
|
return HomeSpacesState(
|
||||||
|
space = CurrentSpace.Root,
|
||||||
spaceRooms = spaceRooms,
|
spaceRooms = spaceRooms,
|
||||||
seenSpaceInvites = seenSpaceInvites,
|
seenSpaceInvites = seenSpaceInvites,
|
||||||
hideInvitesAvatar = hideInvitesAvatar,
|
hideInvitesAvatar = hideInvitesAvatar,
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,14 @@ import io.element.android.libraries.matrix.api.spaces.SpaceRoom
|
||||||
import kotlinx.collections.immutable.ImmutableSet
|
import kotlinx.collections.immutable.ImmutableSet
|
||||||
|
|
||||||
data class HomeSpacesState(
|
data class HomeSpacesState(
|
||||||
|
val space: CurrentSpace,
|
||||||
val spaceRooms: List<SpaceRoom>,
|
val spaceRooms: List<SpaceRoom>,
|
||||||
val seenSpaceInvites: ImmutableSet<SpaceId>,
|
val seenSpaceInvites: ImmutableSet<SpaceId>,
|
||||||
val hideInvitesAvatar: Boolean,
|
val hideInvitesAvatar: Boolean,
|
||||||
val eventSink: (HomeSpacesEvents) -> Unit,
|
val eventSink: (HomeSpacesEvents) -> Unit,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
sealed interface CurrentSpace {
|
||||||
|
object Root : CurrentSpace
|
||||||
|
data class Space(val spaceRoom: SpaceRoom) : CurrentSpace
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,25 @@ open class HomeSpacesStateProvider : PreviewParameterProvider<HomeSpacesState> {
|
||||||
spaceRooms = SpaceRoomProvider().values.toList(),
|
spaceRooms = SpaceRoomProvider().values.toList(),
|
||||||
seenSpaceInvites = setOf(
|
seenSpaceInvites = setOf(
|
||||||
SpaceId("!spaceId3:example.com"),
|
SpaceId("!spaceId3:example.com"),
|
||||||
).toImmutableSet(),
|
),
|
||||||
)
|
),
|
||||||
|
aHomeSpacesState(
|
||||||
|
space = CurrentSpace.Space(
|
||||||
|
spaceRoom = aSpaceRooms(spaceId = SpaceId("!mySpace:example.com"))
|
||||||
|
),
|
||||||
|
spaceRooms = aListOfSpaceRooms(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun aHomeSpacesState(
|
internal fun aHomeSpacesState(
|
||||||
|
space: CurrentSpace = CurrentSpace.Root,
|
||||||
spaceRooms: List<SpaceRoom> = aListOfSpaceRooms(),
|
spaceRooms: List<SpaceRoom> = aListOfSpaceRooms(),
|
||||||
seenSpaceInvites: Set<SpaceId> = emptySet(),
|
seenSpaceInvites: Set<SpaceId> = emptySet(),
|
||||||
hideInvitesAvatar: Boolean = false,
|
hideInvitesAvatar: Boolean = false,
|
||||||
eventSink: (HomeSpacesEvents) -> Unit = {},
|
eventSink: (HomeSpacesEvents) -> Unit = {},
|
||||||
) = HomeSpacesState(
|
) = HomeSpacesState(
|
||||||
|
space = space,
|
||||||
spaceRooms = spaceRooms,
|
spaceRooms = spaceRooms,
|
||||||
seenSpaceInvites = seenSpaceInvites.toImmutableSet(),
|
seenSpaceInvites = seenSpaceInvites.toImmutableSet(),
|
||||||
hideInvitesAvatar = hideInvitesAvatar,
|
hideInvitesAvatar = hideInvitesAvatar,
|
||||||
|
|
@ -38,8 +46,8 @@ internal fun aHomeSpacesState(
|
||||||
|
|
||||||
fun aListOfSpaceRooms(): List<SpaceRoom> {
|
fun aListOfSpaceRooms(): List<SpaceRoom> {
|
||||||
return listOf(
|
return listOf(
|
||||||
aSpaceRooms(),
|
aSpaceRooms(spaceId = SpaceId("!spaceId0:example.com")),
|
||||||
aSpaceRooms(),
|
aSpaceRooms(spaceId = SpaceId("!spaceId1:example.com")),
|
||||||
aSpaceRooms(),
|
aSpaceRooms(spaceId = SpaceId("!spaceId2:example.com")),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,15 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
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.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.matrix.api.core.SpaceId
|
import io.element.android.libraries.matrix.api.core.SpaceId
|
||||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
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
|
@Composable
|
||||||
fun HomeSpacesView(
|
fun HomeSpacesView(
|
||||||
|
|
@ -23,6 +28,29 @@ fun HomeSpacesView(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
LazyColumn(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 {
|
state.spaceRooms.forEach {
|
||||||
item(it.spaceId) {
|
item(it.spaceId) {
|
||||||
val isInvitation = it.state == CurrentUserMembership.INVITED
|
val isInvitation = it.state == CurrentUserMembership.INVITED
|
||||||
|
|
|
||||||
|
|
@ -546,7 +546,7 @@ private fun DefaultLoadedContent(
|
||||||
},
|
},
|
||||||
memberCount = {
|
memberCount = {
|
||||||
if (contentState.showMemberCount) {
|
if (contentState.showMemberCount) {
|
||||||
MembersCountMolecule(memberCount = contentState.numberOfMembers ?: 0)
|
MembersCountMolecule(memberCount = contentState.numberOfMembers?.toInt() ?: 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MembersCountMolecule(
|
fun MembersCountMolecule(
|
||||||
memberCount: Long,
|
memberCount: Int,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -38,11 +38,11 @@ import kotlinx.collections.immutable.persistentListOf
|
||||||
@Composable
|
@Composable
|
||||||
fun SpaceHeaderView(
|
fun SpaceHeaderView(
|
||||||
avatarData: AvatarData,
|
avatarData: AvatarData,
|
||||||
name: String,
|
name: String?,
|
||||||
topic: String,
|
topic: String?,
|
||||||
joinRule: JoinRule,
|
joinRule: JoinRule?,
|
||||||
heroes: ImmutableList<MatrixUser>,
|
heroes: ImmutableList<MatrixUser>,
|
||||||
numberOfMembers: Long,
|
numberOfMembers: Int,
|
||||||
numberOfRooms: Int,
|
numberOfRooms: Int,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
topicMaxLines: Int = Int.MAX_VALUE,
|
topicMaxLines: Int = Int.MAX_VALUE,
|
||||||
|
|
@ -58,29 +58,34 @@ fun SpaceHeaderView(
|
||||||
avatarData = avatarData,
|
avatarData = avatarData,
|
||||||
avatarType = AvatarType.Space(false),
|
avatarType = AvatarType.Space(false),
|
||||||
)
|
)
|
||||||
Text(
|
name?.let {
|
||||||
text = name,
|
Text(
|
||||||
style = ElementTheme.typography.fontHeadingLgBold,
|
text = name,
|
||||||
color = ElementTheme.colors.textPrimary,
|
style = ElementTheme.typography.fontHeadingLgBold,
|
||||||
textAlign = TextAlign.Center,
|
color = ElementTheme.colors.textPrimary,
|
||||||
)
|
textAlign = TextAlign.Center,
|
||||||
SpaceInfoRow(
|
)
|
||||||
joinRule = joinRule,
|
}
|
||||||
numberOfRooms = numberOfRooms,
|
if (joinRule != null)
|
||||||
)
|
SpaceInfoRow(
|
||||||
|
joinRule = joinRule,
|
||||||
|
numberOfRooms = numberOfRooms,
|
||||||
|
)
|
||||||
SpaceMembersView(
|
SpaceMembersView(
|
||||||
heroes = heroes,
|
heroes = heroes,
|
||||||
numberOfMembers = numberOfMembers,
|
numberOfMembers = numberOfMembers,
|
||||||
modifier = Modifier.padding(horizontal = 32.dp),
|
modifier = Modifier.padding(horizontal = 32.dp),
|
||||||
)
|
)
|
||||||
Text(
|
topic?.let {
|
||||||
text = topic,
|
Text(
|
||||||
style = ElementTheme.typography.fontBodyMdRegular,
|
text = topic,
|
||||||
color = ElementTheme.colors.textPrimary,
|
style = ElementTheme.typography.fontBodyMdRegular,
|
||||||
textAlign = TextAlign.Center,
|
color = ElementTheme.colors.textPrimary,
|
||||||
maxLines = topicMaxLines,
|
textAlign = TextAlign.Center,
|
||||||
overflow = TextOverflow.Ellipsis,
|
maxLines = topicMaxLines,
|
||||||
)
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ import kotlinx.collections.immutable.toImmutableList
|
||||||
@Composable
|
@Composable
|
||||||
fun SpaceMembersView(
|
fun SpaceMembersView(
|
||||||
heroes: ImmutableList<MatrixUser>,
|
heroes: ImmutableList<MatrixUser>,
|
||||||
numberOfMembers: Long,
|
numberOfMembers: Int,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
if (heroes.isEmpty()) {
|
if (heroes.isEmpty()) {
|
||||||
|
|
@ -60,7 +60,7 @@ fun SpaceMembersView(
|
||||||
@Composable
|
@Composable
|
||||||
private fun SpaceMembersWithAvatar(
|
private fun SpaceMembersWithAvatar(
|
||||||
heroes: ImmutableList<AvatarData>,
|
heroes: ImmutableList<AvatarData>,
|
||||||
numberOfMembers: Long,
|
numberOfMembers: Int,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue