Room navigation : reuse accept/decline presentation logic
This commit is contained in:
parent
7d59884922
commit
6a255a1b10
23 changed files with 220 additions and 79 deletions
|
|
@ -43,6 +43,10 @@ class InviteListNode @AssistedInject constructor(
|
|||
plugins<InviteListEntryPoint.Callback>().forEach { it.onInviteAccepted(roomId) }
|
||||
}
|
||||
|
||||
private fun onInviteClicked(roomId: RoomId) {
|
||||
plugins<InviteListEntryPoint.Callback>().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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = {},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* 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.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import java.util.Optional
|
||||
|
||||
data class AcceptDeclineInviteState(
|
||||
val invite: Optional<InviteData>,
|
||||
val acceptAction: AsyncAction<RoomId>,
|
||||
val declineAction: AsyncAction<RoomId>,
|
||||
val eventSink: (AcceptDeclineInviteEvents) -> Unit
|
||||
)
|
||||
|
||||
data class InviteData(
|
||||
val roomId: RoomId,
|
||||
val roomName: String,
|
||||
val isDirect: Boolean,
|
||||
)
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* 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 androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import java.util.Optional
|
||||
|
||||
open class AcceptDeclineInviteStateProvider : PreviewParameterProvider<AcceptDeclineInviteState> {
|
||||
override val values: Sequence<AcceptDeclineInviteState>
|
||||
get() = sequenceOf(
|
||||
anAcceptDeclineInviteState(),
|
||||
anAcceptDeclineInviteState(
|
||||
invite = Optional.of(
|
||||
InviteData(RoomId(""), isDirect = true, roomName = "Alice"),
|
||||
),
|
||||
declineAction = AsyncAction.Confirming,
|
||||
),
|
||||
anAcceptDeclineInviteState(
|
||||
invite = Optional.of(
|
||||
InviteData(RoomId(""), isDirect = false, roomName = "Some room"),
|
||||
),
|
||||
declineAction = AsyncAction.Confirming,
|
||||
),
|
||||
anAcceptDeclineInviteState(
|
||||
acceptAction = AsyncAction.Failure(Throwable("Whoops")),
|
||||
),
|
||||
anAcceptDeclineInviteState(
|
||||
declineAction = AsyncAction.Failure(Throwable("Whoops")),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun anAcceptDeclineInviteState(
|
||||
invite: Optional<InviteData> = Optional.empty(),
|
||||
acceptAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
|
||||
declineAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
|
||||
eventSink: (AcceptDeclineInviteEvents) -> Unit = {}
|
||||
) = AcceptDeclineInviteState(
|
||||
invite = invite,
|
||||
acceptAction = acceptAction,
|
||||
declineAction = declineAction,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
|
@ -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)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
package io.element.android.features.invite.impl.response
|
||||
|
||||
sealed 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
|
||||
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
|
||||
}
|
||||
|
|
@ -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<AcceptDeclineInviteState> {
|
||||
) : 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<AsyncAction<RoomId>>) = 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<AsyncAction<RoomId>>) = launch {
|
||||
|
|
@ -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<Plugin>,
|
||||
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
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue