mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-10-31 08:15:02 +00:00
Close the invite screen once the invite has been declined (#7440)
Declining an invite from the full screen invite left the user on that same screen, so they had to press back themselves to get to the room list. Both decline paths are affected: the plain decline handled by AcceptDeclineInviteView, and the decline and block sub screen, which navigated up into the join room flow instead of out of it. Navigate up from the join room flow on a successful decline, and give DeclineInviteAndBlockEntryPoint a callback so the sub screen can report a successful decline separately from a back press. The room list flow supplies the same callback, popping the sub screen once the invite has been declined.
This commit is contained in:
+5
@@ -269,6 +269,11 @@ class HomeFlowNode(
|
||||
parentNode = this,
|
||||
buildContext = buildContext,
|
||||
inviteData = navTarget.inviteData,
|
||||
callback = object : DeclineInviteAndBlockEntryPoint.Callback {
|
||||
override fun onDeclineSuccess() {
|
||||
backstack.pop()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
is NavTarget.SelectNewOwnersWhenLeavingRoom -> {
|
||||
|
||||
+2
-1
@@ -11,6 +11,7 @@ package io.element.android.features.home.impl
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.home.api.HomeEntryPoint
|
||||
import io.element.android.features.invite.test.declineandblock.FakeDeclineInviteAndBlockEntryPoint
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
@@ -36,7 +37,7 @@ class DefaultHomeEntryPointTest : RobolectricTest() {
|
||||
acceptDeclineInviteView = { _, _, _, _ -> lambdaError() },
|
||||
directLogoutView = { _ -> lambdaError() },
|
||||
reportRoomEntryPoint = { _, _, _ -> lambdaError() },
|
||||
declineInviteAndBlockUserEntryPoint = { _, _, _ -> lambdaError() },
|
||||
declineInviteAndBlockUserEntryPoint = FakeDeclineInviteAndBlockEntryPoint(),
|
||||
changeRoomMemberRolesEntryPoint = { _, _, _, _ -> lambdaError() },
|
||||
leaveRoomRenderer = { _, _, _ -> lambdaError() },
|
||||
sessionCoroutineScope = backgroundScope,
|
||||
|
||||
+7
-1
@@ -10,13 +10,19 @@ package io.element.android.features.invite.api.declineandblock
|
||||
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import io.element.android.features.invite.api.InviteData
|
||||
import io.element.android.libraries.architecture.FeatureEntryPoint
|
||||
|
||||
fun interface DeclineInviteAndBlockEntryPoint : FeatureEntryPoint {
|
||||
interface DeclineInviteAndBlockEntryPoint : FeatureEntryPoint {
|
||||
fun createNode(
|
||||
parentNode: Node,
|
||||
buildContext: BuildContext,
|
||||
inviteData: InviteData,
|
||||
callback: Callback,
|
||||
): Node
|
||||
|
||||
interface Callback : Plugin {
|
||||
fun onDeclineSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -17,7 +17,9 @@ import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.features.invite.api.InviteData
|
||||
import io.element.android.features.invite.api.declineandblock.DeclineInviteAndBlockEntryPoint
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.callback
|
||||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
|
||||
@@ -31,6 +33,7 @@ class DeclineAndBlockNode(
|
||||
data class Inputs(val inviteData: InviteData) : NodeInputs
|
||||
|
||||
private val inviteData = inputs<Inputs>().inviteData
|
||||
private val callback: DeclineInviteAndBlockEntryPoint.Callback = callback()
|
||||
private val presenter = presenterFactory.create(inviteData)
|
||||
|
||||
@Composable
|
||||
@@ -39,6 +42,7 @@ class DeclineAndBlockNode(
|
||||
DeclineAndBlockView(
|
||||
state = state,
|
||||
onBackClick = ::navigateUp,
|
||||
onDeclineSuccess = callback::onDeclineSuccess,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
+3
-1
@@ -46,6 +46,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
||||
fun DeclineAndBlockView(
|
||||
state: DeclineAndBlockState,
|
||||
onBackClick: () -> Unit,
|
||||
onDeclineSuccess: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val focusManager = LocalFocusManager.current
|
||||
@@ -53,7 +54,7 @@ fun DeclineAndBlockView(
|
||||
val isDeclining = state.declineAction is AsyncAction.Loading
|
||||
AsyncActionView(
|
||||
async = state.declineAction,
|
||||
onSuccess = { onBackClick() },
|
||||
onSuccess = { onDeclineSuccess() },
|
||||
errorMessage = { stringResource(CommonStrings.error_unknown) },
|
||||
onRetry = { state.eventSink(DeclineAndBlockEvents.Decline) },
|
||||
onErrorDismiss = { state.eventSink(DeclineAndBlockEvents.ClearDeclineAction) }
|
||||
@@ -149,5 +150,6 @@ internal fun DeclineAndBlockViewPreview(
|
||||
DeclineAndBlockView(
|
||||
state = state,
|
||||
onBackClick = {},
|
||||
onDeclineSuccess = {},
|
||||
)
|
||||
}
|
||||
|
||||
+2
-1
@@ -22,8 +22,9 @@ class DefaultDeclineAndBlockEntryPoint : DeclineInviteAndBlockEntryPoint {
|
||||
parentNode: Node,
|
||||
buildContext: BuildContext,
|
||||
inviteData: InviteData,
|
||||
callback: DeclineInviteAndBlockEntryPoint.Callback,
|
||||
): Node {
|
||||
val inputs = DeclineAndBlockNode.Inputs(inviteData)
|
||||
return parentNode.createNode<DeclineAndBlockNode>(buildContext, plugins = listOf(inputs))
|
||||
return parentNode.createNode<DeclineAndBlockNode>(buildContext, plugins = listOf(inputs, callback))
|
||||
}
|
||||
}
|
||||
|
||||
+17
@@ -17,6 +17,7 @@ import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
||||
import io.element.android.features.invite.impl.R
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
||||
import io.element.android.tests.testutils.EventsRecorder
|
||||
@@ -41,6 +42,20 @@ class DeclineAndBlockViewTest : RobolectricTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `a successful decline invokes the expected callback`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<DeclineAndBlockEvents>(expectEvents = false)
|
||||
ensureCalledOnce {
|
||||
setDeclineAndBlockView(
|
||||
aDeclineAndBlockState(
|
||||
declineAction = AsyncAction.Success(Unit),
|
||||
eventSink = eventsRecorder,
|
||||
),
|
||||
onDeclineSuccess = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on decline when enabled emits the expected event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<DeclineAndBlockEvents>()
|
||||
@@ -112,11 +127,13 @@ class DeclineAndBlockViewTest : RobolectricTest() {
|
||||
private fun AndroidComposeUiTest<ComponentActivity>.setDeclineAndBlockView(
|
||||
state: DeclineAndBlockState,
|
||||
onBackClick: () -> Unit = EnsureNeverCalled(),
|
||||
onDeclineSuccess: () -> Unit = EnsureNeverCalled(),
|
||||
) {
|
||||
setContent {
|
||||
DeclineAndBlockView(
|
||||
state = state,
|
||||
onBackClick = onBackClick,
|
||||
onDeclineSuccess = onDeclineSuccess,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -11,7 +11,9 @@ package io.element.android.features.invite.impl.declineandblock
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.invite.api.declineandblock.DeclineInviteAndBlockEntryPoint
|
||||
import io.element.android.features.invite.test.anInviteData
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.node.TestParentNode
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
@@ -31,12 +33,17 @@ class DefaultDeclineAndBlockEntryPointTest {
|
||||
)
|
||||
}
|
||||
val inviteData = anInviteData()
|
||||
val callback = object : DeclineInviteAndBlockEntryPoint.Callback {
|
||||
override fun onDeclineSuccess() = lambdaError()
|
||||
}
|
||||
val result = entryPoint.createNode(
|
||||
parentNode = parentNode,
|
||||
buildContext = BuildContext.root(null),
|
||||
inviteData = inviteData
|
||||
inviteData = inviteData,
|
||||
callback = callback,
|
||||
)
|
||||
assertThat(result).isInstanceOf(DeclineAndBlockNode::class.java)
|
||||
assertThat(result.plugins).contains(DeclineAndBlockNode.Inputs(inviteData))
|
||||
assertThat(result.plugins).contains(callback)
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -19,6 +19,7 @@ class FakeDeclineInviteAndBlockEntryPoint : DeclineInviteAndBlockEntryPoint {
|
||||
parentNode: Node,
|
||||
buildContext: BuildContext,
|
||||
inviteData: InviteData,
|
||||
callback: DeclineInviteAndBlockEntryPoint.Callback,
|
||||
): Node {
|
||||
lambdaError()
|
||||
}
|
||||
|
||||
+4
-1
@@ -69,6 +69,9 @@ class JoinRoomFlowNode(
|
||||
parentNode = this,
|
||||
buildContext = buildContext,
|
||||
inviteData = navTarget.inviteData,
|
||||
callback = object : DeclineInviteAndBlockEntryPoint.Callback {
|
||||
override fun onDeclineSuccess() = navigateUp()
|
||||
},
|
||||
)
|
||||
NavTarget.Root -> rootNode(buildContext)
|
||||
}
|
||||
@@ -99,7 +102,7 @@ class JoinRoomFlowNode(
|
||||
acceptDeclineInviteView.Render(
|
||||
state = state.acceptDeclineInviteState,
|
||||
onAcceptInviteSuccess = {},
|
||||
onDeclineInviteSuccess = {},
|
||||
onDeclineInviteSuccess = { navigateUp() },
|
||||
modifier = Modifier
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user