88package io.element.android.features.space.impl.leave
99
1010import androidx.compose.runtime.Composable
11+ import androidx.compose.runtime.LaunchedEffect
1112import androidx.compose.runtime.MutableState
12- import androidx.compose.runtime.collectAsState
1313import androidx.compose.runtime.getValue
14+ import androidx.compose.runtime.mutableIntStateOf
1415import androidx.compose.runtime.mutableStateOf
15- import androidx.compose.runtime.produceState
1616import androidx.compose.runtime.remember
1717import androidx.compose.runtime.rememberCoroutineScope
18- import dev.zacsweers.metro.Inject
18+ import androidx.compose.runtime.setValue
19+ import dev.zacsweers.metro.Assisted
20+ import dev.zacsweers.metro.AssistedFactory
21+ import dev.zacsweers.metro.AssistedInject
1922import io.element.android.libraries.architecture.AsyncAction
2023import io.element.android.libraries.architecture.AsyncData
2124import io.element.android.libraries.architecture.Presenter
25+ import io.element.android.libraries.architecture.map
2226import io.element.android.libraries.architecture.runUpdatingState
2327import 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
28+ import io.element.android.libraries.matrix.api.spaces.LeaveSpaceHandle
29+ import io.element.android.libraries.matrix.api.spaces.LeaveSpaceRoom
2630import kotlinx.collections.immutable.ImmutableList
27- import kotlinx.collections.immutable.ImmutableSet
2831import kotlinx.collections.immutable.persistentSetOf
29- import kotlinx.collections.immutable.toPersistentList
30- import kotlinx.collections.immutable.toPersistentSet
32+ import kotlinx.collections.immutable.toImmutableList
3133import kotlinx.coroutines.CoroutineScope
3234import kotlinx.coroutines.launch
33- import kotlin.jvm.optionals.getOrNull
3435
35- @Inject
36+ @AssistedInject
3637class 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+
45+ data class LeaveSpaceRooms (
46+ val current : LeaveSpaceRoom ? ,
47+ val others : List <LeaveSpaceRoom >,
48+ )
49+
3950 @Composable
4051 override fun present (): LeaveSpaceState {
4152 val coroutineScope = rememberCoroutineScope()
42- val currentSpace by spaceRoomList.currentSpaceFlow.collectAsState()
53+ var retryCount by remember { mutableIntStateOf( 0 ) }
4354 val leaveSpaceAction = remember {
4455 mutableStateOf<AsyncAction <Unit >>(AsyncAction .Uninitialized )
4556 }
46- val selectedRoomIds = remember {
47- mutableStateOf<ImmutableSet <RoomId >>(persistentSetOf ())
57+ var selectedRoomIds by remember {
58+ mutableStateOf<Collection <RoomId >>(setOf ())
4859 }
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
60+ var leaveSpaceRooms by remember {
61+ mutableStateOf<AsyncData <LeaveSpaceRooms >>(AsyncData .Loading ())
5562 }
56- val selectableSpaceRooms by produceState<AsyncData <ImmutableList <SelectableSpaceRoom >>>(
57- initialValue = AsyncData .Uninitialized ,
58- key1 = joinedSpaceRooms,
59- key2 = selectedRoomIds.value,
60- ) {
61- value = AsyncData .Success (
62- joinedSpaceRooms.map {
63- SelectableSpaceRoom (
64- spaceRoom = it,
65- // TODO Get this value from the SDK
66- isLastAdmin = false ,
67- isSelected = selectedRoomIds.value.contains(it.roomId),
63+ LaunchedEffect (retryCount) {
64+ val rooms = leaveSpaceHandle.rooms()
65+ val (currentRoom, otherRooms) = rooms.getOrNull()
66+ .orEmpty()
67+ .partition { it.spaceRoom.roomId == leaveSpaceHandle.id }
68+ // By default select all rooms that can be left
69+ selectedRoomIds = otherRooms
70+ .filter { it.isLastAdmin.not () }
71+ .map { it.spaceRoom.roomId }
72+ leaveSpaceRooms = rooms.fold(
73+ onSuccess = {
74+ AsyncData .Success (
75+ LeaveSpaceRooms (
76+ current = currentRoom.firstOrNull(),
77+ others = otherRooms.toImmutableList(),
78+ )
6879 )
69- }.toPersistentList()
80+ },
81+ onFailure = { AsyncData .Failure (it) }
7082 )
7183 }
84+ var selectableSpaceRooms by remember {
85+ mutableStateOf<AsyncData <ImmutableList <SelectableSpaceRoom >>>(AsyncData .Loading ())
86+ }
87+ LaunchedEffect (selectedRoomIds, leaveSpaceRooms) {
88+ selectableSpaceRooms = leaveSpaceRooms.map {
89+ it?.others.orEmpty().map { room ->
90+ SelectableSpaceRoom (
91+ spaceRoom = room.spaceRoom,
92+ isLastAdmin = room.isLastAdmin,
93+ isSelected = selectedRoomIds.contains(room.spaceRoom.roomId),
94+ )
95+ }.toImmutableList()
96+ }
97+ }
7298
7399 fun handleEvents (event : LeaveSpaceEvents ) {
74100 when (event) {
101+ LeaveSpaceEvents .Retry -> {
102+ leaveSpaceRooms = AsyncData .Loading ()
103+ retryCount + = 1
104+ }
75105 LeaveSpaceEvents .DeselectAllRooms -> {
76- selectedRoomIds.value = persistentSetOf()
106+ selectedRoomIds = persistentSetOf()
77107 }
78108 LeaveSpaceEvents .SelectAllRooms -> {
79- selectedRoomIds.value = selectableSpaceRooms.dataOrNull()
109+ selectedRoomIds = selectableSpaceRooms.dataOrNull()
80110 .orEmpty()
81111 .filter { it.isLastAdmin.not () }
82112 .map { it.spaceRoom.roomId }
83- .toPersistentSet()
84113 }
85114 is LeaveSpaceEvents .ToggleRoomSelection -> {
86- val currentSet = selectedRoomIds.value
87- selectedRoomIds.value = if (currentSet.contains(event.roomId)) {
88- currentSet - event.roomId
115+ selectedRoomIds = if (selectedRoomIds.contains(event.roomId)) {
116+ selectedRoomIds - event.roomId
89117 } else {
90- currentSet + event.roomId
118+ selectedRoomIds + event.roomId
91119 }
92- .toPersistentSet()
93120 }
94121 LeaveSpaceEvents .LeaveSpace -> coroutineScope.leaveSpace(
95122 leaveSpaceAction = leaveSpaceAction,
96- selectedRoomIds = selectedRoomIds.value ,
123+ selectedRoomIds = selectedRoomIds,
97124 )
98125 LeaveSpaceEvents .CloseError -> {
99126 leaveSpaceAction.value = AsyncAction .Uninitialized
@@ -102,7 +129,8 @@ class LeaveSpacePresenter(
102129 }
103130
104131 return LeaveSpaceState (
105- spaceName = currentSpace.getOrNull()?.name,
132+ spaceName = leaveSpaceRooms.dataOrNull()?.current?.spaceRoom?.name,
133+ isLastAdmin = leaveSpaceRooms.dataOrNull()?.current?.isLastAdmin == true ,
106134 selectableSpaceRooms = selectableSpaceRooms,
107135 leaveSpaceAction = leaveSpaceAction.value,
108136 eventSink = ::handleEvents,
@@ -111,11 +139,10 @@ class LeaveSpacePresenter(
111139
112140 private fun CoroutineScope.leaveSpace (
113141 leaveSpaceAction : MutableState <AsyncAction <Unit >>,
114- @Suppress( " unused " ) selectedRoomIds : Set <RoomId >,
142+ selectedRoomIds : Collection <RoomId >,
115143 ) = launch {
116144 runUpdatingState(leaveSpaceAction) {
117- // TODO SDK API call to leave all the rooms and space
118- Result .failure(Exception (" Not implemented" ))
145+ leaveSpaceHandle.leave(selectedRoomIds.toList())
119146 }
120147 }
121148}
0 commit comments