Skip to content

Commit 83f59c2

Browse files
authored
Merge pull request #5431 from element-hq/feature/fga/space_list_join_action
Feature : space list join action
2 parents 42b2038 + 5e0e0f0 commit 83f59c2

File tree

42 files changed

+829
-80
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+829
-80
lines changed

features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListStateProvider.kt

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,12 @@ import io.element.android.features.home.impl.model.aRoomListRoomSummary
1616
import io.element.android.features.home.impl.model.anInviteSender
1717
import io.element.android.features.home.impl.search.RoomListSearchState
1818
import io.element.android.features.home.impl.search.aRoomListSearchState
19-
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
2019
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
20+
import io.element.android.features.invite.api.acceptdecline.anAcceptDeclineInviteState
2121
import io.element.android.features.leaveroom.api.LeaveRoomEvent
2222
import io.element.android.features.leaveroom.api.LeaveRoomState
23-
import io.element.android.libraries.architecture.AsyncAction
2423
import io.element.android.libraries.designsystem.components.avatar.AvatarData
2524
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
26-
import io.element.android.libraries.matrix.api.core.RoomId
2725
import io.element.android.libraries.push.api.battery.aBatteryOptimizationState
2826
import kotlinx.collections.immutable.ImmutableList
2927
import kotlinx.collections.immutable.persistentListOf
@@ -76,16 +74,6 @@ internal fun aLeaveRoomState(
7674
override val eventSink: (LeaveRoomEvent) -> Unit = eventSink
7775
}
7876

79-
internal fun anAcceptDeclineInviteState(
80-
acceptAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
81-
declineAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
82-
eventSink: (AcceptDeclineInviteEvents) -> Unit = {}
83-
) = AcceptDeclineInviteState(
84-
acceptAction = acceptAction,
85-
declineAction = declineAction,
86-
eventSink = eventSink,
87-
)
88-
8977
internal fun aRoomListRoomSummaryList(): ImmutableList<RoomListRoomSummary> {
9078
return persistentListOf(
9179
aRoomListRoomSummary(

features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ fun HomeSpacesView(
6464
},
6565
onLongClick = {
6666
// TODO
67-
}
67+
},
6868
)
6969
}
7070
}

features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenterTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import io.element.android.features.home.impl.search.aRoomListSearchState
2424
import io.element.android.features.invite.api.SeenInvitesStore
2525
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
2626
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
27+
import io.element.android.features.invite.api.acceptdecline.anAcceptDeclineInviteState
2728
import io.element.android.features.invite.test.InMemorySeenInvitesStore
2829
import io.element.android.features.leaveroom.api.LeaveRoomEvent
2930
import io.element.android.features.leaveroom.api.LeaveRoomState
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright 2024 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
5+
* Please see LICENSE files in the repository root for full details.
6+
*/
7+
8+
package io.element.android.features.invite.api.acceptdecline
9+
10+
import io.element.android.libraries.architecture.AsyncAction
11+
import io.element.android.libraries.matrix.api.core.RoomId
12+
13+
fun anAcceptDeclineInviteState(
14+
acceptAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
15+
declineAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
16+
eventSink: (AcceptDeclineInviteEvents) -> Unit = {},
17+
) = AcceptDeclineInviteState(
18+
acceptAction = acceptAction,
19+
declineAction = declineAction,
20+
eventSink = eventSink,
21+
)

features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/acceptdecline/AcceptDeclineInviteStateProvider.kt

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ package io.element.android.features.invite.impl.acceptdecline
99

1010
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
1111
import io.element.android.features.invite.api.InviteData
12-
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
1312
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
1413
import io.element.android.features.invite.api.acceptdecline.ConfirmingDeclineInvite
14+
import io.element.android.features.invite.api.acceptdecline.anAcceptDeclineInviteState
1515
import io.element.android.features.invite.impl.AcceptInvite
1616
import io.element.android.libraries.architecture.AsyncAction
1717
import io.element.android.libraries.matrix.api.core.RoomId
@@ -51,13 +51,3 @@ open class AcceptDeclineInviteStateProvider : PreviewParameterProvider<AcceptDec
5151
),
5252
)
5353
}
54-
55-
private fun anAcceptDeclineInviteState(
56-
acceptAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
57-
declineAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
58-
eventSink: (AcceptDeclineInviteEvents) -> Unit = {}
59-
) = AcceptDeclineInviteState(
60-
acceptAction = acceptAction,
61-
declineAction = declineAction,
62-
eventSink = eventSink,
63-
)

features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomStateProvider.kt

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ package io.element.android.features.joinroom.impl
99

1010
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
1111
import io.element.android.features.invite.api.InviteData
12-
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
1312
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
13+
import io.element.android.features.invite.api.acceptdecline.anAcceptDeclineInviteState
1414
import io.element.android.libraries.architecture.AsyncAction
1515
import io.element.android.libraries.designsystem.components.avatar.AvatarData
1616
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
@@ -219,16 +219,6 @@ fun aJoinRoomState(
219219
eventSink = eventSink
220220
)
221221

222-
internal fun anAcceptDeclineInviteState(
223-
acceptAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
224-
declineAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
225-
eventSink: (AcceptDeclineInviteEvents) -> Unit = {}
226-
) = AcceptDeclineInviteState(
227-
acceptAction = acceptAction,
228-
declineAction = declineAction,
229-
eventSink = eventSink,
230-
)
231-
232222
internal fun anInviteSender(
233223
userId: UserId = UserId("@bob:domain"),
234224
displayName: String = "Bob",

features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import io.element.android.features.invite.api.InviteData
1313
import io.element.android.features.invite.api.SeenInvitesStore
1414
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
1515
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
16+
import io.element.android.features.invite.api.acceptdecline.anAcceptDeclineInviteState
1617
import io.element.android.features.invite.api.toInviteData
1718
import io.element.android.features.invite.test.InMemorySeenInvitesStore
1819
import io.element.android.features.joinroom.impl.di.CancelKnockRoom

features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceEvents.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77

88
package io.element.android.features.space.impl.root
99

10+
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
11+
1012
sealed interface SpaceEvents {
1113
data object LoadMore : SpaceEvents
14+
data class Join(val spaceRoom: SpaceRoom) : SpaceEvents
15+
data object ClearFailures : SpaceEvents
16+
data class AcceptInvite(val spaceRoom: SpaceRoom) : SpaceEvents
17+
data class DeclineInvite(val spaceRoom: SpaceRoom) : SpaceEvents
1218
}

features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceNode.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import com.bumble.appyx.core.plugin.Plugin
1818
import dev.zacsweers.metro.Assisted
1919
import dev.zacsweers.metro.AssistedInject
2020
import io.element.android.annotations.ContributesNode
21+
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteView
2122
import io.element.android.features.space.impl.di.SpaceFlowScope
2223
import io.element.android.libraries.androidutils.R
2324
import io.element.android.libraries.androidutils.system.startSharePlainTextIntent
@@ -36,11 +37,13 @@ class SpaceNode(
3637
private val presenter: SpacePresenter,
3738
private val matrixClient: MatrixClient,
3839
private val spaceRoomList: SpaceRoomList,
40+
private val acceptDeclineInviteView: AcceptDeclineInviteView,
3941
) : Node(buildContext, plugins = plugins) {
4042
interface Callback : Plugin {
4143
fun onOpenRoom(roomId: RoomId, viaParameters: List<String>)
4244
fun onLeaveSpace()
4345
}
46+
4447
private val callback = plugins.filterIsInstance<Callback>().single()
4548

4649
private fun onShareRoom(context: Context) = lifecycleScope.launch {
@@ -76,6 +79,18 @@ class SpaceNode(
7679
onShareSpace = {
7780
onShareRoom(context)
7881
},
82+
acceptDeclineInviteView = {
83+
acceptDeclineInviteView.Render(
84+
state = state.acceptDeclineInviteState,
85+
onAcceptInviteSuccess = { roomId ->
86+
callback.onOpenRoom(roomId, emptyList())
87+
},
88+
onDeclineInviteSuccess = { roomId ->
89+
// No action needed
90+
},
91+
modifier = Modifier
92+
)
93+
},
7994
modifier = modifier
8095
)
8196
}

features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpacePresenter.kt

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,30 @@ import androidx.compose.runtime.Composable
1111
import androidx.compose.runtime.LaunchedEffect
1212
import androidx.compose.runtime.collectAsState
1313
import androidx.compose.runtime.getValue
14+
import androidx.compose.runtime.mutableStateOf
1415
import androidx.compose.runtime.remember
1516
import androidx.compose.runtime.rememberCoroutineScope
1617
import dev.zacsweers.metro.Inject
18+
import im.vector.app.features.analytics.plan.JoinedRoom
1719
import io.element.android.features.invite.api.SeenInvitesStore
20+
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
21+
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
22+
import io.element.android.features.invite.api.toInviteData
23+
import io.element.android.libraries.architecture.AsyncAction
1824
import io.element.android.libraries.architecture.Presenter
1925
import io.element.android.libraries.core.coroutine.mapState
26+
import io.element.android.libraries.di.annotations.SessionCoroutineScope
2027
import io.element.android.libraries.matrix.api.MatrixClient
28+
import io.element.android.libraries.matrix.api.core.RoomId
29+
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
30+
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
31+
import io.element.android.libraries.matrix.api.room.join.JoinRoom
32+
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
2133
import io.element.android.libraries.matrix.api.spaces.SpaceRoomList
2234
import io.element.android.libraries.matrix.ui.safety.rememberHideInvitesAvatar
2335
import kotlinx.collections.immutable.persistentSetOf
2436
import kotlinx.collections.immutable.toPersistentList
37+
import kotlinx.collections.immutable.toPersistentMap
2538
import kotlinx.collections.immutable.toPersistentSet
2639
import kotlinx.coroutines.CoroutineScope
2740
import kotlinx.coroutines.flow.map
@@ -33,6 +46,9 @@ class SpacePresenter(
3346
private val spaceRoomList: SpaceRoomList,
3447
private val client: MatrixClient,
3548
private val seenInvitesStore: SeenInvitesStore,
49+
private val joinRoom: JoinRoom,
50+
private val acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
51+
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
3652
) : Presenter<SpaceState> {
3753
@Composable
3854
override fun present(): SpaceState {
@@ -44,7 +60,7 @@ class SpacePresenter(
4460
seenInvitesStore.seenRoomIds().map { it.toPersistentSet() }
4561
}.collectAsState(persistentSetOf())
4662

47-
val coroutineScope = rememberCoroutineScope()
63+
val localCoroutineScope = rememberCoroutineScope()
4864
val children by spaceRoomList.spaceRoomsFlow.collectAsState(emptyList())
4965
val hasMoreToLoad by remember {
5066
spaceRoomList.paginationStatusFlow.mapState { status ->
@@ -56,10 +72,40 @@ class SpacePresenter(
5672
}.collectAsState()
5773

5874
val currentSpace by spaceRoomList.currentSpaceFlow.collectAsState()
75+
val (joinActions, setJoinActions) = remember { mutableStateOf(emptyMap<RoomId, AsyncAction<Unit>>()) }
76+
77+
LaunchedEffect(children) {
78+
// Remove joined children from the join actions
79+
val joinedChildren = children
80+
.filter { it.state == CurrentUserMembership.JOINED }
81+
.map { it.roomId }
82+
setJoinActions(joinActions - joinedChildren)
83+
}
84+
85+
val acceptDeclineInviteState = acceptDeclineInvitePresenter.present()
5986

6087
fun handleEvents(event: SpaceEvents) {
6188
when (event) {
62-
SpaceEvents.LoadMore -> coroutineScope.paginate()
89+
SpaceEvents.LoadMore -> localCoroutineScope.paginate()
90+
is SpaceEvents.Join -> {
91+
sessionCoroutineScope.joinRoom(event.spaceRoom, joinActions, setJoinActions)
92+
}
93+
SpaceEvents.ClearFailures -> {
94+
val failedActions = joinActions
95+
.filterValues { it is AsyncAction.Failure }
96+
.mapValues { AsyncAction.Uninitialized }
97+
setJoinActions(joinActions + failedActions)
98+
}
99+
is SpaceEvents.AcceptInvite -> {
100+
acceptDeclineInviteState.eventSink(
101+
AcceptDeclineInviteEvents.AcceptInvite(event.spaceRoom.toInviteData())
102+
)
103+
}
104+
is SpaceEvents.DeclineInvite -> {
105+
acceptDeclineInviteState.eventSink(
106+
AcceptDeclineInviteEvents.DeclineInvite(invite = event.spaceRoom.toInviteData(), shouldConfirm = true, blockUser = false)
107+
)
108+
}
63109
}
64110
}
65111
return SpaceState(
@@ -68,10 +114,27 @@ class SpacePresenter(
68114
seenSpaceInvites = seenSpaceInvites,
69115
hideInvitesAvatar = hideInvitesAvatar,
70116
hasMoreToLoad = hasMoreToLoad,
117+
joinActions = joinActions.toPersistentMap(),
118+
acceptDeclineInviteState = acceptDeclineInviteState,
71119
eventSink = ::handleEvents,
72120
)
73121
}
74122

123+
private fun CoroutineScope.joinRoom(
124+
spaceRoom: SpaceRoom,
125+
joinActions: Map<RoomId, AsyncAction<Unit>>,
126+
setJoinActions: (Map<RoomId, AsyncAction<Unit>>) -> Unit
127+
) = launch {
128+
setJoinActions(joinActions + mapOf(spaceRoom.roomId to AsyncAction.Loading))
129+
joinRoom.invoke(
130+
roomIdOrAlias = spaceRoom.roomId.toRoomIdOrAlias(),
131+
serverNames = spaceRoom.via,
132+
trigger = JoinedRoom.Trigger.SpaceHierarchy,
133+
).onFailure {
134+
setJoinActions(joinActions + mapOf(spaceRoom.roomId to AsyncAction.Failure(it)))
135+
}
136+
}
137+
75138
private fun CoroutineScope.paginate() = launch {
76139
spaceRoomList.paginate()
77140
}

0 commit comments

Comments
 (0)