Merge pull request #4353 from element-hq/feature/fga/room_preview_invite_state

[Change] Invited state room preview
This commit is contained in:
ganfra 2025-03-04 16:45:50 +01:00 committed by GitHub
commit 0d1a35970d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 327 additions and 144 deletions

View file

@ -17,5 +17,5 @@ sealed interface JoinRoomEvents {
data class UpdateKnockMessage(val message: String) : JoinRoomEvents
data object ClearActionStates : JoinRoomEvents
data object AcceptInvite : JoinRoomEvents
data object DeclineInvite : JoinRoomEvents
data class DeclineInvite(val blockUser: Boolean) : JoinRoomEvents
}

View file

@ -152,15 +152,15 @@ class JoinRoomPresenter @AssistedInject constructor(
JoinRoomEvents.JoinRoom -> coroutineScope.joinRoom(joinAction)
is JoinRoomEvents.KnockRoom -> coroutineScope.knockRoom(knockAction, knockMessage)
JoinRoomEvents.AcceptInvite -> {
val inviteData = contentState.toInviteData() ?: return
val inviteData = contentState.toInviteData()
acceptDeclineInviteState.eventSink(
AcceptDeclineInviteEvents.AcceptInvite(inviteData)
)
}
JoinRoomEvents.DeclineInvite -> {
val inviteData = contentState.toInviteData() ?: return
is JoinRoomEvents.DeclineInvite -> {
val inviteData = contentState.toInviteData()
acceptDeclineInviteState.eventSink(
AcceptDeclineInviteEvents.DeclineInvite(inviteData)
AcceptDeclineInviteEvents.DeclineInvite(invite = inviteData, blockUser = event.blockUser)
)
}
is JoinRoomEvents.CancelKnock -> coroutineScope.cancelKnockRoom(event.requiresConfirmation, cancelKnockAction)
@ -314,12 +314,19 @@ private fun JoinRule?.toJoinAuthorisationStatus(): JoinAuthorisationStatus {
@VisibleForTesting
internal fun ContentState.toInviteData(): InviteData? {
return when (this) {
is ContentState.Loaded -> InviteData(
roomId = roomId,
// Note: name should not be null at this point, but use Id just in case...
roomName = name ?: roomId.value,
isDm = isDm
)
is ContentState.Loaded -> {
if (joinAuthorisationStatus is JoinAuthorisationStatus.IsInvited && joinAuthorisationStatus.inviteSender != null) {
InviteData(
roomId = roomId,
// Note: name should not be null at this point, but use Id just in case...
roomName = name ?: roomId.value,
senderId = joinAuthorisationStatus.inviteSender.userId,
isDm = isDm
)
} else {
null
}
}
else -> null
}
}

View file

@ -63,6 +63,7 @@ import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.designsystem.theme.components.TextField
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
@ -105,8 +106,8 @@ fun JoinRoomView(
onAcceptInvite = {
state.eventSink(JoinRoomEvents.AcceptInvite)
},
onDeclineInvite = {
state.eventSink(JoinRoomEvents.DeclineInvite)
onDeclineInvite = { blockUser ->
state.eventSink(JoinRoomEvents.DeclineInvite(blockUser))
},
onJoinRoom = {
state.eventSink(JoinRoomEvents.JoinRoom)
@ -183,7 +184,7 @@ fun JoinRoomView(
private fun JoinRoomFooter(
joinAuthorisationStatus: JoinAuthorisationStatus,
onAcceptInvite: () -> Unit,
onDeclineInvite: () -> Unit,
onDeclineInvite: (Boolean) -> Unit,
onJoinRoom: () -> Unit,
onKnockRoom: () -> Unit,
onCancelKnock: () -> Unit,
@ -193,23 +194,32 @@ private fun JoinRoomFooter(
) {
Box(
modifier = modifier
.fillMaxWidth()
.padding(top = 8.dp)
.fillMaxWidth()
.padding(top = 8.dp)
) {
when (joinAuthorisationStatus) {
is JoinAuthorisationStatus.IsInvited -> {
ButtonRowMolecule(horizontalArrangement = Arrangement.spacedBy(20.dp)) {
OutlinedButton(
text = stringResource(CommonStrings.action_decline),
onClick = onDeclineInvite,
modifier = Modifier.weight(1f),
size = ButtonSize.LargeLowPadding,
)
Button(
text = stringResource(CommonStrings.action_accept),
onClick = onAcceptInvite,
modifier = Modifier.weight(1f),
size = ButtonSize.LargeLowPadding,
Column {
ButtonRowMolecule(horizontalArrangement = Arrangement.spacedBy(20.dp)) {
OutlinedButton(
text = stringResource(CommonStrings.action_decline),
onClick = { onDeclineInvite(false) },
modifier = Modifier.weight(1f),
size = ButtonSize.LargeLowPadding,
)
Button(
text = stringResource(CommonStrings.action_accept),
onClick = onAcceptInvite,
modifier = Modifier.weight(1f),
size = ButtonSize.LargeLowPadding,
)
}
Spacer(modifier = Modifier.height(24.dp))
TextButton(
text = stringResource(R.string.screen_join_room_decline_and_block_button_title),
onClick = { onDeclineInvite(true) },
modifier = Modifier.fillMaxWidth(),
destructive = true
)
}
}
@ -372,12 +382,19 @@ private fun JoinRoomContent(
IsKnockedLoadedContent()
}
else -> {
DefaultLoadedContent(
modifier = Modifier.verticalScroll(rememberScrollState()),
contentState = contentState,
knockMessage = knockMessage,
onKnockMessageUpdate = onKnockMessageUpdate
)
Column(horizontalAlignment = Alignment.CenterHorizontally) {
val inviteSender = (contentState.joinAuthorisationStatus as? JoinAuthorisationStatus.IsInvited)?.inviteSender
if (inviteSender != null) {
InviteSenderView(inviteSender = inviteSender)
Spacer(modifier = Modifier.height(32.dp))
}
DefaultLoadedContent(
modifier = Modifier.verticalScroll(rememberScrollState()),
contentState = contentState,
knockMessage = knockMessage,
onKnockMessageUpdate = onKnockMessageUpdate
)
}
}
}
}
@ -440,8 +457,8 @@ private fun IncompleteContent(
private fun IsKnockedLoadedContent(modifier: Modifier = Modifier) {
BoxWithConstraints(
modifier = modifier
.fillMaxHeight()
.padding(horizontal = 16.dp),
.fillMaxHeight()
.padding(horizontal = 16.dp),
contentAlignment = Alignment.Center,
) {
IconTitleSubtitleMolecule(
@ -487,10 +504,6 @@ private fun DefaultLoadedContent(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
val inviteSender = (contentState.joinAuthorisationStatus as? JoinAuthorisationStatus.IsInvited)?.inviteSender
if (inviteSender != null) {
InviteSenderView(inviteSender = inviteSender)
}
RoomPreviewDescriptionAtom(contentState.topic ?: "")
if (contentState.joinAuthorisationStatus is JoinAuthorisationStatus.CanKnock) {
Spacer(modifier = Modifier.height(24.dp))

View file

@ -167,9 +167,9 @@ class JoinRoomPresenterTest {
awaitItem().also { state ->
state.eventSink(JoinRoomEvents.AcceptInvite)
state.eventSink(JoinRoomEvents.DeclineInvite)
state.eventSink(JoinRoomEvents.DeclineInvite(false))
val inviteData = state.contentState.toInviteData()!!
val inviteData = state.contentState.toInviteData()
assert(eventSinkRecorder)
.isCalledExactly(2)

View file

@ -139,7 +139,7 @@ class JoinRoomViewTest {
}
@Test
fun `clicking on Accept invitation IsInvited room emits the expected Event`() {
fun `clicking on Accept when JoinAuthorisationStatus is IsInvited emits the expected Event`() {
val eventsRecorder = EventsRecorder<JoinRoomEvents>()
rule.setJoinRoomView(
aJoinRoomState(
@ -152,7 +152,7 @@ class JoinRoomViewTest {
}
@Test
fun `clicking on Decline invitation on IsInvited room emits the expected Event`() {
fun `clicking on Decline when JoinAuthorisationStatus is IsInvited emits the expected Event`() {
val eventsRecorder = EventsRecorder<JoinRoomEvents>()
rule.setJoinRoomView(
aJoinRoomState(
@ -161,7 +161,20 @@ class JoinRoomViewTest {
),
)
rule.clickOn(CommonStrings.action_decline)
eventsRecorder.assertSingle(JoinRoomEvents.DeclineInvite)
eventsRecorder.assertSingle(JoinRoomEvents.DeclineInvite(false))
}
@Test
fun `clicking on Decline and block when JoinAuthorisationStatus is IsInvited emits the expected Event`() {
val eventsRecorder = EventsRecorder<JoinRoomEvents>()
rule.setJoinRoomView(
aJoinRoomState(
contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited(null)),
eventSink = eventsRecorder,
),
)
rule.clickOn(R.string.screen_join_room_decline_and_block_button_title)
eventsRecorder.assertSingle(JoinRoomEvents.DeclineInvite(true))
}
@Test