Skip to content

Commit c459af6

Browse files
committed
Leave space: use the SDK API.
1 parent c83fda1 commit c459af6

File tree

16 files changed

+492
-117
lines changed

16 files changed

+492
-117
lines changed

features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpaceNode.kt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,39 @@ package io.element.android.features.space.impl.leave
99

1010
import androidx.compose.runtime.Composable
1111
import androidx.compose.ui.Modifier
12+
import com.bumble.appyx.core.lifecycle.subscribe
1213
import com.bumble.appyx.core.modality.BuildContext
1314
import com.bumble.appyx.core.node.Node
1415
import com.bumble.appyx.core.plugin.Plugin
1516
import dev.zacsweers.metro.Assisted
1617
import dev.zacsweers.metro.AssistedInject
1718
import io.element.android.annotations.ContributesNode
19+
import io.element.android.features.space.api.SpaceEntryPoint
1820
import io.element.android.features.space.impl.di.SpaceFlowScope
21+
import io.element.android.libraries.architecture.inputs
22+
import io.element.android.libraries.matrix.api.MatrixClient
1923

2024
@ContributesNode(SpaceFlowScope::class)
2125
@AssistedInject
2226
class LeaveSpaceNode(
2327
@Assisted buildContext: BuildContext,
2428
@Assisted plugins: List<Plugin>,
25-
private val presenter: LeaveSpacePresenter,
29+
matrixClient: MatrixClient,
30+
presenterFactory: LeaveSpacePresenter.Factory,
2631
) : Node(buildContext, plugins = plugins) {
32+
private val inputs: SpaceEntryPoint.Inputs = inputs()
33+
private val leaveSpaceHandle = matrixClient.spaceService.getLeaveSpaceHandle(inputs.roomId)
34+
private val presenter: LeaveSpacePresenter = presenterFactory.create(leaveSpaceHandle)
35+
36+
override fun onBuilt() {
37+
super.onBuilt()
38+
lifecycle.subscribe(
39+
onDestroy = {
40+
leaveSpaceHandle.close()
41+
}
42+
)
43+
}
44+
2745
@Composable
2846
override fun View(modifier: Modifier) {
2947
val state = presenter.present()

features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpacePresenter.kt

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,65 +9,79 @@ package io.element.android.features.space.impl.leave
99

1010
import androidx.compose.runtime.Composable
1111
import androidx.compose.runtime.MutableState
12-
import androidx.compose.runtime.collectAsState
1312
import androidx.compose.runtime.getValue
1413
import androidx.compose.runtime.mutableStateOf
1514
import androidx.compose.runtime.produceState
1615
import androidx.compose.runtime.remember
1716
import androidx.compose.runtime.rememberCoroutineScope
18-
import dev.zacsweers.metro.Inject
17+
import androidx.compose.runtime.setValue
18+
import dev.zacsweers.metro.Assisted
19+
import dev.zacsweers.metro.AssistedFactory
20+
import dev.zacsweers.metro.AssistedInject
1921
import io.element.android.libraries.architecture.AsyncAction
2022
import io.element.android.libraries.architecture.AsyncData
2123
import io.element.android.libraries.architecture.Presenter
24+
import io.element.android.libraries.architecture.map
2225
import io.element.android.libraries.architecture.runUpdatingState
2326
import io.element.android.libraries.matrix.api.core.RoomId
24-
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
25-
import io.element.android.libraries.matrix.api.spaces.SpaceRoomList
26-
import kotlinx.collections.immutable.ImmutableList
27+
import io.element.android.libraries.matrix.api.spaces.LeaveSpaceHandle
28+
import io.element.android.libraries.matrix.api.spaces.LeaveSpaceRoom
2729
import kotlinx.collections.immutable.ImmutableSet
2830
import kotlinx.collections.immutable.persistentSetOf
29-
import kotlinx.collections.immutable.toPersistentList
31+
import kotlinx.collections.immutable.toImmutableList
3032
import kotlinx.collections.immutable.toPersistentSet
3133
import kotlinx.coroutines.CoroutineScope
3234
import kotlinx.coroutines.launch
33-
import kotlin.jvm.optionals.getOrNull
3435

35-
@Inject
36+
@AssistedInject
3637
class LeaveSpacePresenter(
37-
private val spaceRoomList: SpaceRoomList,
38+
@Assisted private val leaveSpaceHandle: LeaveSpaceHandle,
3839
) : Presenter<LeaveSpaceState> {
40+
@AssistedFactory
41+
fun interface Factory {
42+
fun create(leaveSpaceHandle: LeaveSpaceHandle): LeaveSpacePresenter
43+
}
44+
3945
@Composable
4046
override fun present(): LeaveSpaceState {
4147
val coroutineScope = rememberCoroutineScope()
42-
val currentSpace by spaceRoomList.currentSpaceFlow.collectAsState()
48+
var currentSpace: LeaveSpaceRoom? by remember { mutableStateOf(null) }
4349
val leaveSpaceAction = remember {
4450
mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized)
4551
}
4652
val selectedRoomIds = remember {
4753
mutableStateOf<ImmutableSet<RoomId>>(persistentSetOf())
4854
}
49-
val joinedSpaceRooms by produceState(emptyList()) {
50-
// TODO Get the joined room from the SDK, should also have the isLastAdmin boolean
51-
val rooms = emptyList<SpaceRoom>()
52-
// By default select all rooms
53-
selectedRoomIds.value = rooms.map { it.roomId }.toPersistentSet()
54-
value = rooms
55+
val leaveSpaceRooms by produceState(AsyncData.Loading()) {
56+
val rooms = leaveSpaceHandle.rooms()
57+
val (currentRoom, otherRooms) = rooms.getOrNull()
58+
.orEmpty()
59+
.partition { it.spaceRoom.roomId == leaveSpaceHandle.id }
60+
currentSpace = currentRoom.firstOrNull()
61+
// By default select all rooms that can be left
62+
selectedRoomIds.value = otherRooms
63+
.filter { it.isLastAdmin.not() }
64+
.map { it.spaceRoom.roomId }
65+
.toPersistentSet()
66+
value = rooms.fold(
67+
onSuccess = { AsyncData.Success(otherRooms) },
68+
onFailure = { AsyncData.Failure(it) }
69+
)
5570
}
56-
val selectableSpaceRooms by produceState<AsyncData<ImmutableList<SelectableSpaceRoom>>>(
57-
initialValue = AsyncData.Uninitialized,
58-
key1 = joinedSpaceRooms,
71+
val selectableSpaceRooms by produceState(
72+
initialValue = AsyncData.Loading(),
73+
key1 = leaveSpaceRooms,
5974
key2 = selectedRoomIds.value,
6075
) {
61-
value = AsyncData.Success(
62-
joinedSpaceRooms.map {
76+
value = leaveSpaceRooms.map { list ->
77+
list.orEmpty().map { room ->
6378
SelectableSpaceRoom(
64-
spaceRoom = it,
65-
// TODO Get this value from the SDK
66-
isLastAdmin = false,
67-
isSelected = selectedRoomIds.value.contains(it.roomId),
79+
spaceRoom = room.spaceRoom,
80+
isLastAdmin = room.isLastAdmin,
81+
isSelected = selectedRoomIds.value.contains(room.spaceRoom.roomId),
6882
)
69-
}.toPersistentList()
70-
)
83+
}.toImmutableList()
84+
}
7185
}
7286

7387
fun handleEvents(event: LeaveSpaceEvents) {
@@ -102,7 +116,8 @@ class LeaveSpacePresenter(
102116
}
103117

104118
return LeaveSpaceState(
105-
spaceName = currentSpace.getOrNull()?.name,
119+
spaceName = currentSpace?.spaceRoom?.name,
120+
isLastAdmin = currentSpace?.isLastAdmin == true,
106121
selectableSpaceRooms = selectableSpaceRooms,
107122
leaveSpaceAction = leaveSpaceAction.value,
108123
eventSink = ::handleEvents,
@@ -111,11 +126,10 @@ class LeaveSpacePresenter(
111126

112127
private fun CoroutineScope.leaveSpace(
113128
leaveSpaceAction: MutableState<AsyncAction<Unit>>,
114-
@Suppress("unused") selectedRoomIds: Set<RoomId>,
129+
selectedRoomIds: Set<RoomId>,
115130
) = launch {
116131
runUpdatingState(leaveSpaceAction) {
117-
// TODO SDK API call to leave all the rooms and space
118-
Result.failure(Exception("Not implemented"))
132+
leaveSpaceHandle.leave(selectedRoomIds.toList())
119133
}
120134
}
121135
}

features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpaceState.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import kotlinx.collections.immutable.ImmutableList
1313

1414
data class LeaveSpaceState(
1515
val spaceName: String?,
16+
val isLastAdmin: Boolean,
1617
val selectableSpaceRooms: AsyncData<ImmutableList<SelectableSpaceRoom>>,
1718
val leaveSpaceAction: AsyncAction<Unit>,
1819
val eventSink: (LeaveSpaceEvents) -> Unit,
@@ -25,7 +26,12 @@ data class LeaveSpaceState(
2526
/**
2627
* True if we should show the quick action to select/deselect all rooms.
2728
*/
28-
val showQuickAction = selectableRooms.isNotEmpty()
29+
val showQuickAction = isLastAdmin.not() && selectableRooms.isNotEmpty()
30+
31+
/**
32+
* True if we should show the leave button.
33+
*/
34+
val showLeaveButton = isLastAdmin.not() && selectableSpaceRooms is AsyncData.Success
2935

3036
/**
3137
* True if there all the selectable rooms are selected.

features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpaceStateProvider.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,20 @@ class LeaveSpaceStateProvider : PreviewParameterProvider<LeaveSpaceState> {
105105
aLeaveSpaceState(
106106
selectableSpaceRooms = AsyncData.Failure(Exception("An error")),
107107
),
108+
aLeaveSpaceState(
109+
isLastAdmin = true,
110+
),
108111
)
109112
}
110113

111114
fun aLeaveSpaceState(
112115
spaceName: String? = "Space name",
116+
isLastAdmin: Boolean = false,
113117
selectableSpaceRooms: AsyncData<ImmutableList<SelectableSpaceRoom>> = AsyncData.Uninitialized,
114118
leaveSpaceAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
115119
) = LeaveSpaceState(
116120
spaceName = spaceName,
121+
isLastAdmin = isLastAdmin,
117122
selectableSpaceRooms = selectableSpaceRooms,
118123
leaveSpaceAction = leaveSpaceAction,
119124
eventSink = { }

0 commit comments

Comments
 (0)