feature (space) : add trailing action to SpaceRoomItemView

This commit is contained in:
ganfra 2025-09-24 16:52:56 +02:00
parent 0931244713
commit 7050076beb
4 changed files with 116 additions and 29 deletions

View file

@ -9,6 +9,7 @@ package io.element.android.features.space.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.spaces.SpaceRoom import io.element.android.libraries.matrix.api.spaces.SpaceRoom
import io.element.android.libraries.previewutils.room.aSpaceRoom import io.element.android.libraries.previewutils.room.aSpaceRoom
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
@ -17,24 +18,22 @@ import kotlinx.collections.immutable.toImmutableSet
open class SpaceStateProvider : PreviewParameterProvider<SpaceState> { open class SpaceStateProvider : PreviewParameterProvider<SpaceState> {
override val values: Sequence<SpaceState> override val values: Sequence<SpaceState>
get() = sequenceOf( get() = sequenceOf(
aSpaceState(),
aSpaceState( aSpaceState(
parentSpace = aSpaceRoom(
name = null, ), aSpaceState(
numJoinedMembers = 5, parentSpace = aSpaceRoom(
childrenCount = 10, name = null,
worldReadable = true, numJoinedMembers = 5,
), childrenCount = 10,
hasMoreToLoad = true, worldReadable = true,
), ),
aSpaceState( hasMoreToLoad = true,
hasMoreToLoad = true, ), aSpaceState(
children = aListOfSpaceRooms(), hasMoreToLoad = true,
), children = aListOfSpaceRooms(),
aSpaceState( ), aSpaceState(
hasMoreToLoad = false, hasMoreToLoad = false, children = aListOfSpaceRooms()
children = aListOfSpaceRooms() )
)
// Add other states here // Add other states here
) )
} }
@ -56,13 +55,21 @@ fun aSpaceState(
seenSpaceInvites = seenSpaceInvites.toImmutableSet(), seenSpaceInvites = seenSpaceInvites.toImmutableSet(),
hideInvitesAvatar = hideInvitesAvatar, hideInvitesAvatar = hideInvitesAvatar,
hasMoreToLoad = hasMoreToLoad, hasMoreToLoad = hasMoreToLoad,
eventSink = {} eventSink = {})
)
private fun aListOfSpaceRooms(): List<SpaceRoom> { private fun aListOfSpaceRooms(): List<SpaceRoom> {
return listOf( return listOf(
aSpaceRoom(roomId = RoomId("!spaceId0:example.com")), aSpaceRoom(
aSpaceRoom(roomId = RoomId("!spaceId1:example.com")), roomId = RoomId("!spaceId0:example.com"),
aSpaceRoom(roomId = RoomId("!spaceId2:example.com")), state = null,
),
aSpaceRoom(
roomId = RoomId("!spaceId1:example.com"),
state = CurrentUserMembership.JOINED,
),
aSpaceRoom(
roomId = RoomId("!spaceId2:example.com"),
state = CurrentUserMembership.INVITED,
),
) )
} }

View file

@ -37,6 +37,7 @@ dependencies {
implementation(libs.coil.gif) implementation(libs.coil.gif)
implementation(libs.coil.network.okhttp) implementation(libs.coil.network.okhttp)
implementation(libs.jsoup) implementation(libs.jsoup)
implementation(projects.libraries.previewutils)
testCommonDependencies(libs, true) testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.matrix.test)

View file

@ -20,8 +20,10 @@ 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.width import androidx.compose.foundation.layout.width
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.ripple import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -31,6 +33,7 @@ import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
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
@ -41,8 +44,12 @@ 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.AvatarType
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
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.unreadIndicator import io.element.android.libraries.designsystem.theme.unreadIndicator
import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.room.join.JoinRule
@ -59,6 +66,7 @@ fun SpaceRoomItemView(
onClick: () -> Unit, onClick: () -> Unit,
onLongClick: () -> Unit, onLongClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
trailingAction: @Composable (() -> Unit)? = null,
) { ) {
SpaceRoomItemScaffold( SpaceRoomItemScaffold(
modifier = modifier, modifier = modifier,
@ -67,16 +75,14 @@ fun SpaceRoomItemView(
hideAvatars = hideAvatars, hideAvatars = hideAvatars,
onClick = onClick, onClick = onClick,
onLongClick = onLongClick, onLongClick = onLongClick,
trailingAction = trailingAction,
) { ) {
NameAndIndicatorRow( NameAndIndicatorRow(
isSpace = spaceRoom.isSpace, isSpace = spaceRoom.isSpace, name = spaceRoom.name, showIndicator = showUnreadIndicator
name = spaceRoom.name,
showIndicator = showUnreadIndicator
) )
Spacer(modifier = Modifier.height(1.dp)) Spacer(modifier = Modifier.height(1.dp))
SubtitleRow( SubtitleRow(
visibilityIcon = spaceRoom.visibilityIcon(), visibilityIcon = spaceRoom.visibilityIcon(), subtitle = spaceRoom.subtitle()
subtitle = spaceRoom.subtitle()
) )
Spacer(modifier = Modifier.height(1.dp)) Spacer(modifier = Modifier.height(1.dp))
Text( Text(
@ -166,7 +172,8 @@ private fun SpaceRoomItemScaffold(
onLongClick: () -> Unit, onLongClick: () -> Unit,
hideAvatars: Boolean, hideAvatars: Boolean,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
content: @Composable ColumnScope.() -> Unit trailingAction: @Composable (() -> Unit)? = null,
content: @Composable ColumnScope.() -> Unit,
) { ) {
val clickModifier = Modifier val clickModifier = Modifier
.combinedClickable( .combinedClickable(
@ -174,8 +181,7 @@ private fun SpaceRoomItemScaffold(
onLongClick = onLongClick, onLongClick = onLongClick,
onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), onLongClickLabel = stringResource(CommonStrings.action_open_context_menu),
indication = ripple(), indication = ripple(),
interactionSource = remember { MutableInteractionSource() } interactionSource = remember { MutableInteractionSource() })
)
.onKeyboardContextMenuAction { onLongClick } .onKeyboardContextMenuAction { onLongClick }
Row( Row(
modifier = modifier modifier = modifier
@ -194,6 +200,10 @@ private fun SpaceRoomItemScaffold(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
content = content, content = content,
) )
if (trailingAction != null) {
Spacer(modifier = Modifier.width(16.dp))
trailingAction()
}
} }
} }
@ -233,3 +243,16 @@ private fun SpaceRoom.visibilityIcon(): ImageVector? {
CompoundIcons.LockSolid() CompoundIcons.LockSolid()
} }
} }
@Composable
@PreviewsDayNight
internal fun SpaceRoomItemViewPreview(@PreviewParameter(SpaceRoomProvider::class) spaceRoom: SpaceRoom) = ElementPreview {
SpaceRoomItemView(
spaceRoom = spaceRoom,
showUnreadIndicator = spaceRoom.state == CurrentUserMembership.INVITED,
hideAvatars = false,
onClick = {},
onLongClick = {},
modifier = Modifier.fillMaxWidth()
)
}

View file

@ -0,0 +1,56 @@
/*
* 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.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
import io.element.android.libraries.previewutils.room.aSpaceRoom
class SpaceRoomProvider : PreviewParameterProvider<SpaceRoom> {
override val values: Sequence<SpaceRoom> = sequenceOf(
aSpaceRoom(
roomType = RoomType.Room,
name = "Room name",
topic = "Room topic that is quite long and might be truncated"
),
aSpaceRoom(
numJoinedMembers = 5,
childrenCount = 10,
worldReadable = true,
roomId = RoomId("!spaceId0:example.com"),
),
aSpaceRoom(
numJoinedMembers = 5,
childrenCount = 10,
worldReadable = true,
avatarUrl = "anUrl",
roomId = RoomId("!spaceId1:example.com"),
),
aSpaceRoom(
name = null,
numJoinedMembers = 5,
childrenCount = 10,
worldReadable = true,
avatarUrl = "anUrl",
roomId = RoomId("!spaceId2:example.com"),
state = CurrentUserMembership.INVITED,
),
aSpaceRoom(
name = null,
numJoinedMembers = 5,
childrenCount = 10,
worldReadable = true,
avatarUrl = "anUrl",
roomId = RoomId("!spaceId3:example.com"),
state = CurrentUserMembership.INVITED,
),
)
}