Merge pull request #5449 from element-hq/feature/fga/room_list_space_invite

Room list space invite
This commit is contained in:
ganfra
2025-10-03 13:17:28 +02:00
committed by GitHub
17 changed files with 92 additions and 41 deletions

View File

@@ -189,10 +189,14 @@ private fun RoomSummaryScaffoldRow(
) {
Avatar(
avatarData = room.avatarData,
avatarType = AvatarType.Room(
heroes = room.heroes,
isTombstoned = room.isTombstoned,
),
avatarType = if (room.isSpace) {
AvatarType.Space(isTombstoned = room.isTombstoned)
} else {
AvatarType.Room(
heroes = room.heroes,
isTombstoned = room.isTombstoned,
)
},
hideImage = hideAvatarImage,
)
Spacer(modifier = Modifier.width(16.dp))

View File

@@ -69,6 +69,7 @@ class RoomListRoomSummaryFactory(
user.getAvatarData(size = AvatarSize.RoomListItem)
}.toImmutableList(),
isTombstoned = roomInfo.successorRoom != null,
isSpace = roomInfo.isSpace,
)
}
}

View File

@@ -38,6 +38,7 @@ data class RoomListRoomSummary(
val inviteSender: InviteSender?,
val isTombstoned: Boolean,
val heroes: ImmutableList<AvatarData>,
val isSpace: Boolean,
) {
val isHighlighted = userDefinedNotificationMode != RoomNotificationMode.MUTE &&
(numberOfUnreadNotifications > 0 || numberOfUnreadMentions > 0) ||

View File

@@ -102,6 +102,15 @@ open class RoomListRoomSummaryProvider : PreviewParameterProvider<RoomListRoomSu
displayName = "Bob",
),
),
aRoomListRoomSummary(
name = "A space invite",
displayType = RoomSummaryDisplayType.INVITE,
inviteSender = anInviteSender(
userId = UserId("@bob:matrix.org"),
displayName = "Bob",
),
isSpace = true
),
aRoomListRoomSummary(
name = "A knocked room",
displayType = RoomSummaryDisplayType.KNOCKED,
@@ -151,6 +160,7 @@ internal fun aRoomListRoomSummary(
canonicalAlias: RoomAlias? = null,
heroes: List<AvatarData> = emptyList(),
isTombstoned: Boolean = false,
isSpace: Boolean = false,
) = RoomListRoomSummary(
id = id,
roomId = RoomId(id),
@@ -172,4 +182,5 @@ internal fun aRoomListRoomSummary(
canonicalAlias = canonicalAlias,
heroes = heroes.toImmutableList(),
isTombstoned = isTombstoned,
isSpace = isSpace
)

View File

@@ -85,6 +85,7 @@ internal fun createRoomListRoomSummary(
heroes: List<AvatarData> = emptyList(),
timestamp: String? = null,
isTombstoned: Boolean = false,
isSpace: Boolean = false,
) = RoomListRoomSummary(
id = A_ROOM_ID.value,
roomId = A_ROOM_ID,
@@ -106,4 +107,5 @@ internal fun createRoomListRoomSummary(
isDm = false,
heroes = heroes.toPersistentList(),
isTombstoned = isTombstoned,
isSpace = isSpace
)

View File

@@ -58,11 +58,12 @@ sealed interface RoomListFilter {
data object Invite : RoomListFilter
/**
* A filter that matches either Group or People rooms.
* A filter that matches either Group,People rooms or Space.
*/
sealed interface Category : RoomListFilter {
data object Group : Category
data object People : Category
data object Space : Category
}
/**

View File

@@ -29,7 +29,6 @@ import org.matrix.rustcomponents.sdk.RoomList as InnerRoomList
private val ROOM_LIST_RUST_FILTERS = listOf(
RoomListEntriesDynamicFilterKind.NonLeft,
RoomListEntriesDynamicFilterKind.NonSpace,
RoomListEntriesDynamicFilterKind.DeduplicateVersions
)

View File

@@ -15,41 +15,57 @@ import io.element.android.libraries.matrix.api.roomlist.RoomSummary
val RoomListFilter.predicate
get() = when (this) {
is RoomListFilter.All -> { _: RoomSummary -> true }
is RoomListFilter.Any -> { _: RoomSummary -> true }
RoomListFilter.None -> { _: RoomSummary -> false }
is RoomListFilter.All -> { roomSummary -> NonSpacePredicate(roomSummary) || IsInvitedPredicate(roomSummary) }
is RoomListFilter.Any -> { roomSummary -> NonSpacePredicate(roomSummary) || IsInvitedPredicate(roomSummary) }
RoomListFilter.None -> { _ -> false }
RoomListFilter.Category.Group -> { roomSummary: RoomSummary ->
!roomSummary.info.isDm && !roomSummary.isInvited()
!roomSummary.info.isDm && NonInvitedPredicate(roomSummary) && NonSpacePredicate(roomSummary)
}
RoomListFilter.Category.People -> { roomSummary: RoomSummary ->
roomSummary.info.isDm && !roomSummary.isInvited()
roomSummary.info.isDm && NonInvitedPredicate(roomSummary) && NonSpacePredicate(roomSummary)
}
RoomListFilter.Category.Space -> IsSpacePredicate
RoomListFilter.Favorite -> { roomSummary: RoomSummary ->
roomSummary.info.isFavorite && !roomSummary.isInvited()
roomSummary.info.isFavorite && NonInvitedPredicate(roomSummary) && NonSpacePredicate(roomSummary)
}
RoomListFilter.Unread -> { roomSummary: RoomSummary ->
!roomSummary.isInvited() && (roomSummary.info.numUnreadNotifications > 0 || roomSummary.info.isMarkedUnread)
NonInvitedPredicate(roomSummary) &&
NonSpacePredicate(roomSummary) &&
(roomSummary.info.numUnreadNotifications > 0 || roomSummary.info.isMarkedUnread)
}
is RoomListFilter.NormalizedMatchRoomName -> { roomSummary: RoomSummary ->
roomSummary.info.name?.withoutAccents().orEmpty().contains(normalizedPattern, ignoreCase = true)
}
RoomListFilter.Invite -> { roomSummary: RoomSummary ->
roomSummary.isInvited()
roomSummary.info.name?.withoutAccents().orEmpty().contains(normalizedPattern, ignoreCase = true) &&
(NonSpacePredicate(roomSummary) || IsInvitedPredicate(roomSummary))
}
RoomListFilter.Invite -> IsInvitedPredicate
}
fun List<RoomSummary>.filter(filter: RoomListFilter): List<RoomSummary> {
return when (filter) {
is RoomListFilter.All -> {
val predicates = filter.filters.map { it.predicate }
val predicates = if (filter.filters.isNotEmpty()) {
filter.filters.map { it.predicate }
} else {
listOf(filter.predicate)
}
filter { roomSummary -> predicates.all { it(roomSummary) } }
}
is RoomListFilter.Any -> {
val predicates = filter.filters.map { it.predicate }
val predicates = if (filter.filters.isNotEmpty()) {
filter.filters.map { it.predicate }
} else {
listOf(filter.predicate)
}
filter { roomSummary -> predicates.any { it(roomSummary) } }
}
else -> filter(filter.predicate)
}
}
private fun RoomSummary.isInvited() = info.currentUserMembership == CurrentUserMembership.INVITED
private val IsSpacePredicate = { roomSummary: RoomSummary -> roomSummary.info.isSpace }
private val NonSpacePredicate = { roomSummary: RoomSummary -> !IsSpacePredicate(roomSummary) }
private val IsInvitedPredicate = { roomSummary: RoomSummary -> roomSummary.info.currentUserMembership == CurrentUserMembership.INVITED }
private val NonInvitedPredicate = { roomSummary: RoomSummary -> !IsInvitedPredicate(roomSummary) }

View File

@@ -41,6 +41,14 @@ class RoomListFilterTest {
currentUserMembership = CurrentUserMembership.INVITED
)
private val space = aRoomSummary(
isSpace = true
)
private val invitedSpace = aRoomSummary(
isSpace = true,
currentUserMembership = CurrentUserMembership.INVITED
)
private val roomSummaries = listOf(
regularRoom,
dmRoom,
@@ -49,13 +57,15 @@ class RoomListFilterTest {
unreadNotificationRoom,
roomToSearch,
roomWithAccent,
invitedRoom
invitedRoom,
space,
invitedSpace,
)
@Test
fun `Room list filter all empty`() = runTest {
val filter = RoomListFilter.all()
assertThat(roomSummaries.filter(filter)).isEqualTo(roomSummaries)
assertThat(roomSummaries.filter(filter)).isEqualTo(roomSummaries - space)
}
@Test
@@ -83,6 +93,12 @@ class RoomListFilterTest {
)
}
@Test
fun `Room list filter space`() = runTest {
val filter = RoomListFilter.Category.Space
assertThat(roomSummaries.filter(filter)).containsExactly(space, invitedSpace)
}
@Test
fun `Room list filter favorite`() = runTest {
val filter = RoomListFilter.Favorite
@@ -98,7 +114,7 @@ class RoomListFilterTest {
@Test
fun `Room list filter invites`() = runTest {
val filter = RoomListFilter.Invite
assertThat(roomSummaries.filter(filter)).containsExactly(invitedRoom)
assertThat(roomSummaries.filter(filter)).containsExactly(invitedRoom, invitedSpace)
}
@Test
@@ -136,10 +152,4 @@ class RoomListFilterTest {
)
assertThat(roomSummaries.filter(filter)).isEmpty()
}
@Test
fun `Room list filter all with empty list`() = runTest {
val filter = RoomListFilter.all()
assertThat(roomSummaries.filter(filter)).isEqualTo(roomSummaries)
}
}