mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 12:07:28 +00:00
Hide space children you have left that can only be joined by invitation
After leaving a room listed in a space, the room stayed in the child list with a Join button, even though it can only be entered with a new invitation. It disappeared only after leaving and reopening the space, because the server omits it from the refetched hierarchy. Apply the same rule locally in the presenter. The filter keys on the LEFT membership combined with an invite join rule rather than on the derived visibility, which collapses knock and unknown join rules into private and would wrongly remove the Join button from knockable rooms.
This commit is contained in:
+10
-3
@@ -35,6 +35,7 @@ import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRoom
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
|
||||
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
|
||||
import io.element.android.libraries.matrix.api.spaces.SpaceRoomList
|
||||
@@ -117,12 +118,14 @@ class SpacePresenter(
|
||||
|
||||
val filteredChildren by remember {
|
||||
derivedStateOf {
|
||||
val notRemoved = children.filterNot { it.roomId in removedRoomIds }
|
||||
val visibleChildren = children
|
||||
.filterNot { it.roomId in removedRoomIds }
|
||||
.filterNot { it.cannotBeRejoined() }
|
||||
if (isManageMode) {
|
||||
// In manage mode, only show rooms (not spaces)
|
||||
notRemoved.filter { !it.isSpace }.toImmutableList()
|
||||
visibleChildren.filter { !it.isSpace }.toImmutableList()
|
||||
} else {
|
||||
notRemoved.toImmutableList()
|
||||
visibleChildren.toImmutableList()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,3 +257,7 @@ class SpacePresenter(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun SpaceRoom.cannotBeRejoined(): Boolean {
|
||||
return state == CurrentUserMembership.LEFT && joinRule == JoinRule.Invite
|
||||
}
|
||||
|
||||
+74
@@ -30,11 +30,13 @@ import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
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.room.join.JoinRoom
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.spaces.SpaceRoomList
|
||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID_3
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID_4
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
||||
import io.element.android.libraries.matrix.test.room.join.FakeJoinRoom
|
||||
@@ -537,6 +539,78 @@ class SpacePresenterTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - left children which can only be joined by invitation are filtered out`() = runTest {
|
||||
val leftInviteOnlyRoom = aSpaceRoom(
|
||||
roomId = A_ROOM_ID,
|
||||
roomType = RoomType.Room,
|
||||
state = CurrentUserMembership.LEFT,
|
||||
joinRule = JoinRule.Invite,
|
||||
)
|
||||
val leftPublicRoom = aSpaceRoom(
|
||||
roomId = A_ROOM_ID_2,
|
||||
roomType = RoomType.Room,
|
||||
state = CurrentUserMembership.LEFT,
|
||||
joinRule = JoinRule.Public,
|
||||
)
|
||||
val leftKnockRoom = aSpaceRoom(
|
||||
roomId = A_ROOM_ID_3,
|
||||
roomType = RoomType.Room,
|
||||
state = CurrentUserMembership.LEFT,
|
||||
joinRule = JoinRule.Knock,
|
||||
)
|
||||
val leftRoomWithUnknownJoinRule = aSpaceRoom(
|
||||
roomId = A_ROOM_ID_4,
|
||||
roomType = RoomType.Room,
|
||||
state = CurrentUserMembership.LEFT,
|
||||
joinRule = null,
|
||||
)
|
||||
val fakeSpaceRoomList = FakeSpaceRoomList(
|
||||
initialSpaceRoomsValue = listOf(leftInviteOnlyRoom, leftPublicRoom, leftKnockRoom, leftRoomWithUnknownJoinRule),
|
||||
paginateResult = { Result.success(Unit) },
|
||||
)
|
||||
val presenter = createSpacePresenter(spaceRoomList = fakeSpaceRoomList)
|
||||
presenter.test {
|
||||
awaitItem()
|
||||
advanceUntilIdle()
|
||||
val stateWithChildren = expectMostRecentItem()
|
||||
assertThat(stateWithChildren.children).containsExactly(leftPublicRoom, leftKnockRoom, leftRoomWithUnknownJoinRule)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - children which can only be joined by invitation are kept when not left`() = runTest {
|
||||
val joinedRoom = aSpaceRoom(
|
||||
roomId = A_ROOM_ID,
|
||||
roomType = RoomType.Room,
|
||||
state = CurrentUserMembership.JOINED,
|
||||
joinRule = JoinRule.Invite,
|
||||
)
|
||||
val invitedRoom = aSpaceRoom(
|
||||
roomId = A_ROOM_ID_2,
|
||||
roomType = RoomType.Room,
|
||||
state = CurrentUserMembership.INVITED,
|
||||
joinRule = JoinRule.Invite,
|
||||
)
|
||||
val roomWithUnknownMembership = aSpaceRoom(
|
||||
roomId = A_ROOM_ID_3,
|
||||
roomType = RoomType.Room,
|
||||
state = null,
|
||||
joinRule = JoinRule.Invite,
|
||||
)
|
||||
val fakeSpaceRoomList = FakeSpaceRoomList(
|
||||
initialSpaceRoomsValue = listOf(joinedRoom, invitedRoom, roomWithUnknownMembership),
|
||||
paginateResult = { Result.success(Unit) },
|
||||
)
|
||||
val presenter = createSpacePresenter(spaceRoomList = fakeSpaceRoomList)
|
||||
presenter.test {
|
||||
awaitItem()
|
||||
advanceUntilIdle()
|
||||
val stateWithChildren = expectMostRecentItem()
|
||||
assertThat(stateWithChildren.children).containsExactly(joinedRoom, invitedRoom, roomWithUnknownMembership)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - removed rooms persist after flow update on partial failure`() = runTest {
|
||||
// On partial failure, successfully removed rooms should stay filtered even after flow updates
|
||||
|
||||
Reference in New Issue
Block a user