Replace SpaceState.currentSpace with spaceInfo (RoomInfo)

This commit is contained in:
ganfra
2026-01-15 17:37:34 +01:00
parent b560b0443e
commit aeeaa48df7
6 changed files with 86 additions and 78 deletions

View File

@@ -53,7 +53,6 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlin.jvm.optionals.getOrNull
@Inject
class SpacePresenter(
@@ -103,7 +102,6 @@ class SpacePresenter(
val canAccessSpaceSettings by remember {
derivedStateOf { isSpaceSettingsEnabled && permissions.settingsPermissions.hasAny(roomInfo.joinRule) }
}
val currentSpace by spaceRoomList.currentSpaceFlow.collectAsState()
val (joinActions, setJoinActions) = remember { mutableStateOf(emptyMap<RoomId, AsyncAction<Unit>>()) }
var topicViewerState: TopicViewerState by remember { mutableStateOf(TopicViewerState.Hidden) }
@@ -216,8 +214,7 @@ class SpacePresenter(
}
}
return SpaceState(
currentSpaceId = spaceRoomList.roomId,
currentSpace = currentSpace.getOrNull(),
spaceInfo = roomInfo,
children = filteredChildren,
seenSpaceInvites = seenSpaceInvites,
hideInvitesAvatar = hideInvitesAvatar,

View File

@@ -12,14 +12,14 @@ import androidx.compose.runtime.Immutable
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.RoomInfo
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.ImmutableMap
import kotlinx.collections.immutable.ImmutableSet
data class SpaceState(
private val currentSpaceId: RoomId,
val currentSpace: SpaceRoom?,
val spaceInfo: RoomInfo,
val children: ImmutableList<SpaceRoom>,
val seenSpaceInvites: ImmutableSet<RoomId>,
val hideInvitesAvatar: Boolean,
@@ -40,8 +40,6 @@ data class SpaceState(
it is AsyncAction.Failure
}
val currentSpaceDisplayName = currentSpace?.displayName ?: currentSpaceId.value
val showManageRoomsAction: Boolean = canEditSpaceGraph && children.any { spaceRoom -> !spaceRoom.isSpace }
val selectedCount: Int = selectedRoomIds.size
val isRemoveButtonEnabled: Boolean = selectedRoomIds.isNotEmpty()

View File

@@ -15,6 +15,8 @@ import io.element.android.features.invite.api.acceptdecline.anAcceptDeclineInvit
import io.element.android.libraries.architecture.AsyncAction
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.RoomInfo
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
import io.element.android.libraries.previewutils.room.aSpaceRoom
@@ -27,11 +29,11 @@ open class SpaceStateProvider : PreviewParameterProvider<SpaceState> {
override val values: Sequence<SpaceState>
get() = sequenceOf(
aSpaceState(),
aSpaceState(parentSpace = aParentSpace(joinRule = JoinRule.Public)),
aSpaceState(parentSpace = aParentSpace(joinRule = JoinRule.Restricted(persistentListOf()))),
aSpaceState(spaceInfo = aSpaceInfo(joinRule = JoinRule.Public)),
aSpaceState(spaceInfo = aSpaceInfo(joinRule = JoinRule.Restricted(persistentListOf()))),
aSpaceState(children = aListOfSpaceRooms()),
aSpaceState(
parentSpace = aParentSpace(),
spaceInfo = aSpaceInfo(),
children = aListOfSpaceRooms(),
joiningRooms = setOf(RoomId("!spaceId0:example.com")),
hasMoreToLoad = false
@@ -41,19 +43,19 @@ open class SpaceStateProvider : PreviewParameterProvider<SpaceState> {
),
// Manage mode states
aSpaceState(
parentSpace = aParentSpace(),
spaceInfo = aSpaceInfo(),
children = aListOfSpaceRooms(),
isManageMode = true,
selectedRoomIds = emptySet(),
),
aSpaceState(
parentSpace = aParentSpace(),
spaceInfo = aSpaceInfo(),
children = aListOfSpaceRooms(),
isManageMode = true,
selectedRoomIds = setOf(RoomId("!spaceId0:example.com"), RoomId("!spaceId1:example.com")),
),
aSpaceState(
parentSpace = aParentSpace(),
spaceInfo = aSpaceInfo(),
children = aListOfSpaceRooms(),
isManageMode = true,
selectedRoomIds = setOf(RoomId("!spaceId0:example.com")),
@@ -63,7 +65,7 @@ open class SpaceStateProvider : PreviewParameterProvider<SpaceState> {
}
fun aSpaceState(
parentSpace: SpaceRoom = aParentSpace(),
spaceInfo: RoomInfo = aSpaceInfo(),
children: List<SpaceRoom> = emptyList(),
seenSpaceInvites: Set<RoomId> = emptySet(),
joiningRooms: Set<RoomId> = emptySet(),
@@ -79,8 +81,7 @@ fun aSpaceState(
removeRoomsAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
eventSink: (SpaceEvents) -> Unit = { },
) = SpaceState(
currentSpaceId = parentSpace.roomId,
currentSpace = parentSpace,
spaceInfo = spaceInfo,
children = children.toImmutableList(),
seenSpaceInvites = seenSpaceInvites.toImmutableSet(),
hideInvitesAvatar = hideInvitesAvatar,
@@ -96,16 +97,45 @@ fun aSpaceState(
eventSink = eventSink,
)
private fun aParentSpace(
private fun aSpaceInfo(
joinRule: JoinRule? = null,
): SpaceRoom {
return aSpaceRoom(
numJoinedMembers = 5,
childrenCount = 10,
worldReadable = true,
joinRule = joinRule,
roomId = RoomId("!spaceId0:example.com"),
): RoomInfo {
return RoomInfo(
id = RoomId("!spaceId0:example.com"),
name = "A Space",
rawName = "A Space",
topic = "Space description goes here. " + LoremIpsum(20).values.first(),
avatarUrl = null,
isPublic = true,
isDirect = false,
isEncrypted = false,
joinRule = joinRule,
isSpace = true,
isFavorite = false,
canonicalAlias = null,
alternativeAliases = persistentListOf(),
currentUserMembership = CurrentUserMembership.JOINED,
inviter = null,
activeMembersCount = 5,
invitedMembersCount = 0,
joinedMembersCount = 5,
roomPowerLevels = null,
highlightCount = 0,
notificationCount = 0,
userDefinedNotificationMode = null,
hasRoomCall = false,
activeRoomCallParticipants = persistentListOf(),
isMarkedUnread = false,
numUnreadMessages = 0,
numUnreadNotifications = 0,
numUnreadMentions = 0,
heroes = persistentListOf(),
pinnedEventIds = persistentListOf(),
creators = persistentListOf(),
historyVisibility = RoomHistoryVisibility.Joined,
successorRoom = null,
roomVersion = "11",
privilegedCreatorRole = false,
)
}

View File

@@ -77,7 +77,9 @@ 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.components.TopAppBar
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.RoomInfo
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
import io.element.android.libraries.matrix.api.spaces.SpaceRoomVisibility
import io.element.android.libraries.matrix.ui.components.JoinButton
import io.element.android.libraries.matrix.ui.components.SpaceHeaderView
import io.element.android.libraries.matrix.ui.components.SpaceRoomItemView
@@ -131,7 +133,7 @@ fun SpaceView(
exit = fadeOut()
) {
SpaceViewTopBar(
currentSpace = state.currentSpace,
spaceInfo = state.spaceInfo,
canAccessSpaceSettings = state.canAccessSpaceSettings,
showManageRoomsAction = state.showManageRoomsAction,
onBackClick = onBackClick,
@@ -166,7 +168,7 @@ fun SpaceView(
eventSink = state.eventSink
)
RemoveRoomsActionView(
spaceDisplayName = state.currentSpaceDisplayName,
spaceDisplayName = state.spaceInfo.name ?: state.spaceInfo.id.value,
removeRoomsAction = state.removeRoomsAction,
selectedCount = state.selectedCount,
onConfirm = { state.eventSink(SpaceEvents.ConfirmRoomRemoval) },
@@ -235,8 +237,7 @@ private fun SpaceViewContent(
modifier: Modifier = Modifier,
) {
LazyColumn(modifier.fillMaxSize()) {
val currentSpace = state.currentSpace
if (currentSpace != null) {
val spaceInfo = state.spaceInfo
item(key = "space_header") {
AnimatedVisibility(
!state.isManageMode,
@@ -245,20 +246,19 @@ private fun SpaceViewContent(
) {
Column {
SpaceHeaderView(
avatarData = currentSpace.getAvatarData(AvatarSize.SpaceHeader),
name = currentSpace.displayName,
topic = currentSpace.topic,
avatarData = spaceInfo.getAvatarData(AvatarSize.SpaceHeader),
name = spaceInfo.name,
topic = spaceInfo.topic,
topicMaxLines = 2,
visibility = currentSpace.visibility,
heroes = currentSpace.heroes.toImmutableList(),
numberOfMembers = currentSpace.numJoinedMembers,
visibility = SpaceRoomVisibility.fromJoinRule(spaceInfo.joinRule),
heroes = spaceInfo.heroes,
numberOfMembers = spaceInfo.joinedMembersCount.toInt(),
onTopicClick = onTopicClick
)
HorizontalDivider()
}
}
}
}
itemsIndexed(
items = state.children,
key = { _, spaceRoom -> spaceRoom.roomId }
@@ -337,7 +337,7 @@ private fun LoadingMoreIndicator(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun SpaceViewTopBar(
currentSpace: SpaceRoom?,
spaceInfo: RoomInfo,
canAccessSpaceSettings: Boolean,
showManageRoomsAction: Boolean,
onBackClick: () -> Unit,
@@ -354,16 +354,14 @@ private fun SpaceViewTopBar(
BackButton(onClick = onBackClick)
},
title = {
if (currentSpace != null) {
val roundedCornerShape = RoundedCornerShape(8.dp)
SpaceAvatarAndNameRow(
name = currentSpace.displayName,
avatarData = currentSpace.getAvatarData(AvatarSize.TimelineRoom),
name = spaceInfo.name,
avatarData = spaceInfo.getAvatarData(AvatarSize.TimelineRoom),
modifier = Modifier
.clip(roundedCornerShape)
.clickable(enabled = canAccessSpaceSettings, onClick = onSettingsClick)
)
}
},
actions = {
var showMenu by remember { mutableStateOf(false) }

View File

@@ -36,6 +36,7 @@ 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.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.join.FakeJoinRoom
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.matrix.test.spaces.FakeSpaceRoomList
@@ -63,7 +64,7 @@ class SpacePresenterTest {
val presenter = createSpacePresenter(spaceRoomList = spaceRoomList)
presenter.test {
val state = awaitItem()
assertThat(state.currentSpace).isNull()
assertThat(state.spaceInfo).isNotNull()
assertThat(state.children).isEmpty()
assertThat(state.seenSpaceInvites).isEmpty()
assertThat(state.hideInvitesAvatar).isFalse()
@@ -143,23 +144,6 @@ class SpacePresenterTest {
}
}
@Test
fun `present - current space value`() = runTest {
val paginateResult = lambdaRecorder<Result<Unit>> {
Result.success(Unit)
}
val spaceRoomList = FakeSpaceRoomList(paginateResult = paginateResult)
val presenter = createSpacePresenter(spaceRoomList = spaceRoomList)
presenter.test {
val state = awaitItem()
advanceUntilIdle()
assertThat(state.currentSpace).isNull()
val aSpace = aSpaceRoom()
spaceRoomList.emitCurrentSpace(aSpace)
assertThat(awaitItem().currentSpace).isEqualTo(aSpace)
}
}
@Test
fun `present - children value`() = runTest {
val paginateResult = lambdaRecorder<Result<Unit>> {

View File

@@ -22,6 +22,7 @@ import io.element.android.libraries.matrix.api.spaces.SpaceRoom
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.A_ROOM_TOPIC
import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.previewutils.room.aSpaceRoom
import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.tests.testutils.EnsureNeverCalled
@@ -127,7 +128,7 @@ class SpaceViewTest {
val eventsRecorder = EventsRecorder<SpaceEvents>()
rule.setSpaceView(
aSpaceState(
parentSpace = aSpaceRoom(topic = A_ROOM_TOPIC),
spaceInfo = aRoomInfo(topic = A_ROOM_TOPIC),
hasMoreToLoad = false,
eventSink = eventsRecorder,
)