diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt index 580c4b2d36..6be8633f7f 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt @@ -43,6 +43,7 @@ class HomeSpacesPresenter @Inject constructor( } return HomeSpacesState( + space = CurrentSpace.Root, spaceRooms = spaceRooms, seenSpaceInvites = seenSpaceInvites, hideInvitesAvatar = hideInvitesAvatar, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesState.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesState.kt index 9d727b2a65..6def46c7b3 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesState.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesState.kt @@ -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, val seenSpaceInvites: ImmutableSet, val hideInvitesAvatar: Boolean, val eventSink: (HomeSpacesEvents) -> Unit, ) + +sealed interface CurrentSpace { + object Root : CurrentSpace + data class Space(val spaceRoom: SpaceRoom) : CurrentSpace +} diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesStateProvider.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesStateProvider.kt index 794fe1d16f..466f515b26 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesStateProvider.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesStateProvider.kt @@ -19,17 +19,25 @@ open class HomeSpacesStateProvider : PreviewParameterProvider { 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 = aListOfSpaceRooms(), seenSpaceInvites: Set = 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 { return listOf( - aSpaceRooms(), - aSpaceRooms(), - aSpaceRooms(), + aSpaceRooms(spaceId = SpaceId("!spaceId0:example.com")), + aSpaceRooms(spaceId = SpaceId("!spaceId1:example.com")), + aSpaceRooms(spaceId = SpaceId("!spaceId2:example.com")), ) } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt index 1f99a8b6c6..be6639e94b 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt @@ -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 diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt index d20e1fe596..03598425e9 100644 --- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt +++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt @@ -546,7 +546,7 @@ private fun DefaultLoadedContent( }, memberCount = { if (contentState.showMemberCount) { - MembersCountMolecule(memberCount = contentState.numberOfMembers ?: 0) + MembersCountMolecule(memberCount = contentState.numberOfMembers?.toInt() ?: 0) } } ) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/MembersCountMolecule.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/MembersCountMolecule.kt index 844376af85..fa22b8a50a 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/MembersCountMolecule.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/MembersCountMolecule.kt @@ -26,7 +26,7 @@ import io.element.android.libraries.designsystem.theme.components.Text @Composable fun MembersCountMolecule( - memberCount: Long, + memberCount: Int, modifier: Modifier = Modifier, ) { Row( diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceHeaderRootView.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceHeaderRootView.kt new file mode 100644 index 0000000000..22ef102946 --- /dev/null +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceHeaderRootView.kt @@ -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, + ) +} diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceHeaderView.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceHeaderView.kt index ab33b6f637..8c3f1c51bd 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceHeaderView.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceHeaderView.kt @@ -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, - 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, + ) + } } } diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceMembersView.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceMembersView.kt index c63743c51e..0c7bc9a37d 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceMembersView.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceMembersView.kt @@ -35,7 +35,7 @@ import kotlinx.collections.immutable.toImmutableList @Composable fun SpaceMembersView( heroes: ImmutableList, - numberOfMembers: Long, + numberOfMembers: Int, modifier: Modifier = Modifier, ) { if (heroes.isEmpty()) { @@ -60,7 +60,7 @@ fun SpaceMembersView( @Composable private fun SpaceMembersWithAvatar( heroes: ImmutableList, - numberOfMembers: Long, + numberOfMembers: Int, modifier: Modifier = Modifier, ) { Row(