diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index 8ba98e5a6b..4b82cb6992 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -350,6 +350,10 @@ class LoggedInFlowNode @AssistedInject constructor( backstack.pop() } + override fun onInviteClicked(roomId: RoomId) { + backstack.push(NavTarget.Room(roomId)) + } + override fun onInviteAccepted(roomId: RoomId) { backstack.push(NavTarget.Room(roomId)) } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomNode.kt index cccc66ddfb..3574b37e2d 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomNode.kt @@ -24,6 +24,7 @@ import com.bumble.appyx.core.plugin.Plugin import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.invite.api.response.AcceptDeclineInviteView import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.SessionScope @@ -34,6 +35,7 @@ class JoinRoomNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, presenterFactory: JoinRoomPresenter.Factory, + private val acceptDeclineInviteView: AcceptDeclineInviteView, ) : Node(buildContext, plugins = plugins) { data class Inputs( @@ -51,5 +53,11 @@ class JoinRoomNode @AssistedInject constructor( onBackPressed = ::navigateUp, modifier = modifier ) + acceptDeclineInviteView.Render( + state = state.acceptDeclineInviteState, + onInviteAccepted = {}, + onInviteDeclined = { navigateUp() }, + modifier = Modifier + ) } } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomPresenter.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomPresenter.kt index d80fb99b3e..60a59652bf 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomPresenter.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomPresenter.kt @@ -20,16 +20,17 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.produceState -import androidx.compose.runtime.rememberCoroutineScope import dagger.assisted.Assisted import dagger.assisted.AssistedInject +import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents +import io.element.android.features.invite.api.response.AcceptDeclineInvitePresenter +import io.element.android.features.invite.api.response.InviteData import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.api.MatrixClient 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.roomlist.RoomListService -import kotlinx.coroutines.launch import java.util.Optional import kotlin.jvm.optionals.getOrNull @@ -37,6 +38,7 @@ class JoinRoomPresenter @AssistedInject constructor( @Assisted private val roomId: RoomId, private val matrixClient: MatrixClient, private val roomListService: RoomListService, + private val acceptDeclineInvitePresenter: AcceptDeclineInvitePresenter, ) : Presenter { interface Factory { @@ -47,6 +49,7 @@ class JoinRoomPresenter @AssistedInject constructor( override fun present(): JoinRoomState { val userMembership by roomListService.getUserMembershipForRoom(roomId).collectAsState(initial = Optional.empty()) val joinAuthorisationStatus = joinAuthorisationStatus(userMembership) + val acceptDeclineInviteState = acceptDeclineInvitePresenter.present() val roomInfo by produceState>(initialValue = AsyncData.Uninitialized, key1 = userMembership) { value = when { userMembership.isPresent -> { @@ -56,6 +59,7 @@ class JoinRoomPresenter @AssistedInject constructor( roomName = it.displayName, roomAlias = it.alias, memberCount = it.activeMemberCount, + isDirect = it.isDirect, roomAvatarUrl = it.avatarUrl ) } @@ -65,21 +69,17 @@ class JoinRoomPresenter @AssistedInject constructor( } } - val coroutineScope = rememberCoroutineScope() - fun handleEvents(event: JoinRoomEvents) { when (event) { JoinRoomEvents.AcceptInvite, JoinRoomEvents.JoinRoom -> { - coroutineScope.launch { - matrixClient.joinRoom(roomId) - } + acceptDeclineInviteState.eventSink( + AcceptDeclineInviteEvents.AcceptInvite(roomInfo.toInviteData()) + ) } JoinRoomEvents.DeclineInvite -> { - coroutineScope.launch { - matrixClient.getRoom(roomId)?.use { - it.leave() - } - } + acceptDeclineInviteState.eventSink( + AcceptDeclineInviteEvents.DeclineInvite(roomInfo.toInviteData()) + ) } } } @@ -87,11 +87,21 @@ class JoinRoomPresenter @AssistedInject constructor( return JoinRoomState( roomInfo = roomInfo, joinAuthorisationStatus = joinAuthorisationStatus, - currentAction = CurrentAction.None, + acceptDeclineInviteState = acceptDeclineInviteState, eventSink = ::handleEvents ) } + private fun AsyncData.toInviteData(): InviteData { + return dataOrNull().let { + InviteData( + roomId = roomId, + roomName = it?.roomName ?: "", + isDirect = it?.isDirect ?: false + ) + } + } + @Composable private fun joinAuthorisationStatus(userMembership: Optional): JoinAuthorisationStatus { return when { diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomState.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomState.kt index 2e95987d97..ca9f71baba 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomState.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomState.kt @@ -17,6 +17,7 @@ package io.element.android.appnav.room.join import androidx.compose.runtime.Immutable +import io.element.android.features.invite.api.response.AcceptDeclineInviteState import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize @@ -26,7 +27,7 @@ import io.element.android.libraries.matrix.api.core.RoomId data class JoinRoomState( val roomInfo: AsyncData, val joinAuthorisationStatus: JoinAuthorisationStatus, - val currentAction: CurrentAction, + val acceptDeclineInviteState: AcceptDeclineInviteState, val eventSink: (JoinRoomEvents) -> Unit ){ val showMemberCount = roomInfo.dataOrNull()?.memberCount != null @@ -37,6 +38,7 @@ data class RoomInfo( val roomName: String, val roomAlias: String?, val memberCount: Long?, + val isDirect: Boolean, val roomAvatarUrl: String?, ) { fun avatarData(size: AvatarSize): AvatarData { @@ -55,7 +57,3 @@ enum class JoinAuthorisationStatus { CanJoin, Unknown, } - -sealed interface CurrentAction { - data object None : CurrentAction -} diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomStateProvider.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomStateProvider.kt index 928edb4ce4..6ac24cbdcb 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomStateProvider.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/join/JoinRoomStateProvider.kt @@ -17,6 +17,8 @@ package io.element.android.appnav.room.join import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.features.invite.api.response.AcceptDeclineInviteState +import io.element.android.features.invite.api.response.anAcceptDeclineInviteState import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.matrix.api.core.RoomId @@ -45,16 +47,17 @@ fun aJoinRoomState( roomName = "Element x android", roomAlias = "#exa:matrix.org", memberCount = null, + isDirect = false, roomAvatarUrl = null ) ), joinAuthorisationStatus: JoinAuthorisationStatus = JoinAuthorisationStatus.Unknown, - currentAction: CurrentAction = CurrentAction.None, + acceptDeclineInviteState: AcceptDeclineInviteState = anAcceptDeclineInviteState(), eventSink: (JoinRoomEvents) -> Unit = {} ) = JoinRoomState( roomInfo = roomInfo, joinAuthorisationStatus = joinAuthorisationStatus, - currentAction = currentAction, + acceptDeclineInviteState = acceptDeclineInviteState, eventSink = eventSink ) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/join/di/JoinRoomModule.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/join/di/JoinRoomModule.kt index fa7635a312..15b7f72ef0 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/join/di/JoinRoomModule.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/join/di/JoinRoomModule.kt @@ -20,6 +20,7 @@ import com.squareup.anvil.annotations.ContributesTo import dagger.Module import dagger.Provides import io.element.android.appnav.room.join.JoinRoomPresenter +import io.element.android.features.invite.api.response.AcceptDeclineInvitePresenter import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId @@ -32,13 +33,15 @@ object JoinRoomModule { fun providesJoinRoomPresenterFactory( roomListService: RoomListService, client: MatrixClient, + acceptDeclineInvitePresenter: AcceptDeclineInvitePresenter, ): JoinRoomPresenter.Factory { return object : JoinRoomPresenter.Factory { override fun create(roomId: RoomId): JoinRoomPresenter { return JoinRoomPresenter( roomId = roomId, matrixClient = client, - roomListService = roomListService + roomListService = roomListService, + acceptDeclineInvitePresenter = acceptDeclineInvitePresenter, ) } } diff --git a/features/invite/api/build.gradle.kts b/features/invite/api/build.gradle.kts index 1781ee93ae..52df82e38a 100644 --- a/features/invite/api/build.gradle.kts +++ b/features/invite/api/build.gradle.kts @@ -15,7 +15,7 @@ */ plugins { - id("io.element.android-library") + id("io.element.android-compose-library") } android { diff --git a/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/InviteListEntryPoint.kt b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/InviteListEntryPoint.kt index 6abfe8f518..c5063cdbc8 100644 --- a/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/InviteListEntryPoint.kt +++ b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/InviteListEntryPoint.kt @@ -32,7 +32,7 @@ interface InviteListEntryPoint : FeatureEntryPoint { interface Callback : Plugin { fun onBackClicked() - + fun onInviteClicked(roomId: RoomId) fun onInviteAccepted(roomId: RoomId) } } diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteEvents.kt b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInviteEvents.kt similarity index 68% rename from features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteEvents.kt rename to features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInviteEvents.kt index 17d60cca37..8365ba3a90 100644 --- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteEvents.kt +++ b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInviteEvents.kt @@ -14,13 +14,9 @@ * limitations under the License. */ -package io.element.android.features.invite.impl.response +package io.element.android.features.invite.api.response -sealed interface AcceptDeclineInviteEvents { +interface AcceptDeclineInviteEvents { data class AcceptInvite(val invite: InviteData) : AcceptDeclineInviteEvents data class DeclineInvite(val invite: InviteData) : AcceptDeclineInviteEvents - data object ConfirmDeclineInvite : AcceptDeclineInviteEvents - data object CancelDeclineInvite : AcceptDeclineInviteEvents - data object DismissAcceptError : AcceptDeclineInviteEvents - data object DismissDeclineError : AcceptDeclineInviteEvents } diff --git a/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInvitePresenter.kt b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInvitePresenter.kt new file mode 100644 index 0000000000..7ca0158c2b --- /dev/null +++ b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInvitePresenter.kt @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.invite.api.response + +import io.element.android.libraries.architecture.Presenter + +interface AcceptDeclineInvitePresenter: Presenter diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteState.kt b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInviteState.kt similarity index 80% rename from features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteState.kt rename to features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInviteState.kt index 11b960f57b..95980f0ac3 100644 --- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteState.kt +++ b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInviteState.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.invite.impl.response +package io.element.android.features.invite.api.response import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.RoomId @@ -24,11 +24,5 @@ data class AcceptDeclineInviteState( val invite: Optional, val acceptAction: AsyncAction, val declineAction: AsyncAction, - val eventSink: (AcceptDeclineInviteEvents) -> Unit -) - -data class InviteData( - val roomId: RoomId, - val roomName: String, - val isDirect: Boolean, + val eventSink: (AcceptDeclineInviteEvents) -> Unit, ) diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteStateProvider.kt b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInviteStateProvider.kt similarity index 97% rename from features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteStateProvider.kt rename to features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInviteStateProvider.kt index 710c8b7538..e6a20d9b80 100644 --- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteStateProvider.kt +++ b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInviteStateProvider.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.invite.impl.response +package io.element.android.features.invite.api.response import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.architecture.AsyncAction diff --git a/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInviteView.kt b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInviteView.kt new file mode 100644 index 0000000000..c969458122 --- /dev/null +++ b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInviteView.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.invite.api.response + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import io.element.android.libraries.matrix.api.core.RoomId + +interface AcceptDeclineInviteView { + @Composable + fun Render( + state: AcceptDeclineInviteState, + onInviteAccepted: (RoomId) -> Unit, + onInviteDeclined: (RoomId) -> Unit, + modifier: Modifier, + ) +} diff --git a/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/InviteData.kt b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/InviteData.kt new file mode 100644 index 0000000000..081da0bfc6 --- /dev/null +++ b/features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/InviteData.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.invite.api.response + +import io.element.android.libraries.matrix.api.core.RoomId + +data class InviteData( + val roomId: RoomId, + val roomName: String, + val isDirect: Boolean, +) diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListNode.kt b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListNode.kt index 53c5b31095..fe491b157e 100644 --- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListNode.kt +++ b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListNode.kt @@ -43,6 +43,10 @@ class InviteListNode @AssistedInject constructor( plugins().forEach { it.onInviteAccepted(roomId) } } + private fun onInviteClicked(roomId: RoomId) { + plugins().forEach { it.onInviteClicked(roomId) } + } + @Composable override fun View(modifier: Modifier) { val state = presenter.present() @@ -50,7 +54,8 @@ class InviteListNode @AssistedInject constructor( state = state, onBackClicked = ::onBackClicked, onInviteAccepted = ::onInviteAccepted, - onInviteDeclined = {} + onInviteDeclined = {}, + onInviteClicked = ::onInviteClicked, ) } } diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListPresenter.kt b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListPresenter.kt index a46f135aa3..971e255898 100644 --- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListPresenter.kt +++ b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListPresenter.kt @@ -24,11 +24,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import io.element.android.features.invite.api.SeenInvitesStore +import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents +import io.element.android.features.invite.api.response.AcceptDeclineInvitePresenter +import io.element.android.features.invite.api.response.InviteData import io.element.android.features.invite.impl.model.InviteListInviteSummary import io.element.android.features.invite.impl.model.InviteSender -import io.element.android.features.invite.impl.response.AcceptDeclineInviteEvents -import io.element.android.features.invite.impl.response.AcceptDeclineInvitePresenter -import io.element.android.features.invite.impl.response.InviteData import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListState.kt b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListState.kt index 60d8778c33..8a3cd69923 100644 --- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListState.kt +++ b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListState.kt @@ -17,7 +17,7 @@ package io.element.android.features.invite.impl.invitelist import androidx.compose.runtime.Immutable -import io.element.android.features.invite.impl.response.AcceptDeclineInviteState +import io.element.android.features.invite.api.response.AcceptDeclineInviteState import io.element.android.features.invite.impl.model.InviteListInviteSummary import kotlinx.collections.immutable.ImmutableList diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListStateProvider.kt b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListStateProvider.kt index 11902e4673..e796896745 100644 --- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListStateProvider.kt +++ b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListStateProvider.kt @@ -17,11 +17,11 @@ package io.element.android.features.invite.impl.invitelist import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.features.invite.api.response.AcceptDeclineInviteState import io.element.android.features.invite.impl.model.InviteListInviteSummary import io.element.android.features.invite.impl.model.InviteSender -import io.element.android.features.invite.impl.response.AcceptDeclineInviteState -import io.element.android.features.invite.impl.response.AcceptDeclineInviteStateProvider -import io.element.android.features.invite.impl.response.anAcceptDeclineInviteState +import io.element.android.features.invite.api.response.AcceptDeclineInviteStateProvider +import io.element.android.features.invite.api.response.anAcceptDeclineInviteState import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId import kotlinx.collections.immutable.ImmutableList diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListView.kt b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListView.kt index 2ad75e43eb..16031d558c 100644 --- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListView.kt +++ b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListView.kt @@ -16,6 +16,7 @@ package io.element.android.features.invite.impl.invitelist +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.consumeWindowInsets @@ -53,11 +54,13 @@ fun InviteListView( onBackClicked: () -> Unit, onInviteAccepted: (RoomId) -> Unit, onInviteDeclined: (RoomId) -> Unit, + onInviteClicked: (RoomId) -> Unit, modifier: Modifier = Modifier, ) { InviteListContent( state = state, modifier = modifier, + onInviteClicked = onInviteClicked, onBackClicked = onBackClicked, ) AcceptDeclineInviteView( @@ -72,6 +75,7 @@ fun InviteListView( private fun InviteListContent( state: InviteListState, onBackClicked: () -> Unit, + onInviteClicked: (RoomId) -> Unit, modifier: Modifier = Modifier, ) { Scaffold( @@ -112,6 +116,9 @@ private fun InviteListContent( items = state.inviteList, ) { index, invite -> InviteSummaryRow( + modifier = Modifier.clickable( + onClick = { onInviteClicked(invite.roomId) } + ), invite = invite, onAcceptClicked = { state.eventSink(InviteListEvents.AcceptInvite(invite)) }, onDeclineClicked = { state.eventSink(InviteListEvents.DeclineInvite(invite)) }, @@ -136,5 +143,6 @@ internal fun InviteListViewPreview(@PreviewParameter(InviteListStateProvider::cl onBackClicked = {}, onInviteAccepted = {}, onInviteDeclined = {}, + onInviteClicked = {}, ) } diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteView.kt b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteView.kt index a214fed4a2..f1462e8dba 100644 --- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteView.kt +++ b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteView.kt @@ -22,6 +22,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewParameter +import io.element.android.features.invite.api.response.AcceptDeclineInviteState +import io.element.android.features.invite.api.response.AcceptDeclineInviteStateProvider +import io.element.android.features.invite.api.response.InviteData import io.element.android.features.invite.impl.R import io.element.android.libraries.designsystem.components.async.AsyncActionView import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog @@ -42,14 +45,14 @@ fun AcceptDeclineInviteView( async = state.acceptAction, onSuccess = onInviteAccepted, onErrorDismiss = { - state.eventSink(AcceptDeclineInviteEvents.DismissAcceptError) + state.eventSink(DefaultAcceptDeclineInviteEvents.DismissAcceptError) }, ) AsyncActionView( async = state.declineAction, onSuccess = onInviteDeclined, onErrorDismiss = { - state.eventSink(AcceptDeclineInviteEvents.DismissDeclineError) + state.eventSink(DefaultAcceptDeclineInviteEvents.DismissDeclineError) }, confirmationDialog = { val invite = state.invite.getOrNull() @@ -57,10 +60,10 @@ fun AcceptDeclineInviteView( DeclineConfirmationDialog( invite = invite, onConfirmClicked = { - state.eventSink(AcceptDeclineInviteEvents.ConfirmDeclineInvite) + state.eventSink(DefaultAcceptDeclineInviteEvents.ConfirmDeclineInvite) }, onDismissClicked = { - state.eventSink(AcceptDeclineInviteEvents.CancelDeclineInvite) + state.eventSink(DefaultAcceptDeclineInviteEvents.CancelDeclineInvite) } ) } diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/DefaultAcceptDeclineInviteEvents.kt b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/DefaultAcceptDeclineInviteEvents.kt new file mode 100644 index 0000000000..4698b1ba2d --- /dev/null +++ b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/DefaultAcceptDeclineInviteEvents.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.invite.impl.response + +import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents + +sealed interface DefaultAcceptDeclineInviteEvents: AcceptDeclineInviteEvents { + data object ConfirmDeclineInvite : DefaultAcceptDeclineInviteEvents + data object CancelDeclineInvite : DefaultAcceptDeclineInviteEvents + data object DismissAcceptError : DefaultAcceptDeclineInviteEvents + data object DismissDeclineError : DefaultAcceptDeclineInviteEvents +} diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/DefaultAcceptDeclineInvitePresenter.kt similarity index 78% rename from features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt rename to features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/DefaultAcceptDeclineInvitePresenter.kt index 38302377f1..ccdcf1e27a 100644 --- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt +++ b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/DefaultAcceptDeclineInvitePresenter.kt @@ -23,10 +23,16 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue +import com.squareup.anvil.annotations.ContributesBinding import im.vector.app.features.analytics.plan.JoinedRoom +import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents +import io.element.android.features.invite.api.response.AcceptDeclineInvitePresenter +import io.element.android.features.invite.api.response.AcceptDeclineInviteState +import io.element.android.features.invite.api.response.InviteData import io.element.android.libraries.architecture.AsyncAction -import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState +import io.element.android.libraries.architecture.runUpdatingState +import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.push.api.notifications.NotificationDrawerManager @@ -38,11 +44,12 @@ import java.util.Optional import javax.inject.Inject import kotlin.jvm.optionals.getOrNull -class AcceptDeclineInvitePresenter @Inject constructor( +@ContributesBinding(SessionScope::class) +class DefaultAcceptDeclineInvitePresenter @Inject constructor( private val client: MatrixClient, private val analyticsService: AnalyticsService, private val notificationDrawerManager: NotificationDrawerManager, -) : Presenter { +) : AcceptDeclineInvitePresenter { @Composable override fun present(): AcceptDeclineInviteState { @@ -66,7 +73,7 @@ class AcceptDeclineInvitePresenter @Inject constructor( declinedAction.value = AsyncAction.Confirming } - is AcceptDeclineInviteEvents.ConfirmDeclineInvite -> { + is DefaultAcceptDeclineInviteEvents.ConfirmDeclineInvite -> { declinedAction.value = AsyncAction.Uninitialized currentInvite.getOrNull()?.let { localCoroutineScope.declineInvite(it.roomId, declinedAction) @@ -74,16 +81,16 @@ class AcceptDeclineInvitePresenter @Inject constructor( currentInvite = Optional.empty() } - is AcceptDeclineInviteEvents.CancelDeclineInvite -> { + is DefaultAcceptDeclineInviteEvents.CancelDeclineInvite -> { currentInvite = Optional.empty() declinedAction.value = AsyncAction.Uninitialized } - is AcceptDeclineInviteEvents.DismissAcceptError -> { + is DefaultAcceptDeclineInviteEvents.DismissAcceptError -> { acceptedAction.value = AsyncAction.Uninitialized } - is AcceptDeclineInviteEvents.DismissDeclineError -> { + is DefaultAcceptDeclineInviteEvents.DismissDeclineError -> { declinedAction.value = AsyncAction.Uninitialized } } @@ -98,14 +105,14 @@ class AcceptDeclineInvitePresenter @Inject constructor( } private fun CoroutineScope.acceptInvite(roomId: RoomId, acceptedAction: MutableState>) = launch { - suspend { - client.getRoom(roomId)?.use { - it.join().getOrThrow() + acceptedAction.runUpdatingState { + client.joinRoom(roomId).onSuccess { notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId, doRender = true) - analyticsService.capture(it.toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite)) + client.getRoom(roomId)?.use { room -> + analyticsService.capture(room.toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite)) + } } - roomId - }.runCatchingUpdatingState(acceptedAction) + } } private fun CoroutineScope.declineInvite(roomId: RoomId, declinedAction: MutableState>) = launch { diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteNode.kt b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/DefaultAcceptDeclineInviteView.kt similarity index 56% rename from features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteNode.kt rename to features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/DefaultAcceptDeclineInviteView.kt index 4718b38881..b87f5fa655 100644 --- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteNode.kt +++ b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/DefaultAcceptDeclineInviteView.kt @@ -18,28 +18,27 @@ package io.element.android.features.invite.impl.response import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import com.bumble.appyx.core.modality.BuildContext -import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.plugin.Plugin -import dagger.assisted.Assisted -import dagger.assisted.AssistedInject -import io.element.android.anvilannotations.ContributesNode +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.invite.api.response.AcceptDeclineInviteState +import io.element.android.features.invite.api.response.AcceptDeclineInviteView import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.core.RoomId +import javax.inject.Inject -@ContributesNode(SessionScope::class) -class AcceptDeclineInviteNode @AssistedInject constructor( - @Assisted buildContext: BuildContext, - @Assisted plugins: List, - private val presenter: AcceptDeclineInvitePresenter, -) : Node(buildContext, plugins = plugins) { +@ContributesBinding(SessionScope::class) +class DefaultAcceptDeclineInviteView @Inject constructor() : AcceptDeclineInviteView { @Composable - override fun View(modifier: Modifier) { - val state = presenter.present() + override fun Render( + state: AcceptDeclineInviteState, + onInviteAccepted: (RoomId) -> Unit, + onInviteDeclined: (RoomId) -> Unit, + modifier: Modifier, + ) { AcceptDeclineInviteView( state = state, - onInviteAccepted = {}, - onInviteDeclined = {}, + onInviteAccepted = onInviteAccepted, + onInviteDeclined = onInviteDeclined, modifier = modifier ) }