Let JoinRoomView render the InviteSender
This commit is contained in:
@@ -38,7 +38,11 @@ import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.preview.RoomPreview
|
||||
import io.element.android.libraries.matrix.ui.model.InviteSender
|
||||
import io.element.android.libraries.matrix.ui.model.toInviteSender
|
||||
import kotlinx.coroutines.flow.first
|
||||
import java.util.Optional
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
class JoinRoomPresenter @AssistedInject constructor(
|
||||
@Assisted private val roomId: RoomId,
|
||||
@@ -74,10 +78,22 @@ class JoinRoomPresenter @AssistedInject constructor(
|
||||
else -> {
|
||||
value = ContentState.Loading(roomIdOrAlias)
|
||||
val result = matrixClient.getRoomPreview(roomId.toRoomIdOrAlias())
|
||||
value = result.fold(
|
||||
onSuccess = { it.toContentState() },
|
||||
result.fold(
|
||||
onSuccess = {
|
||||
value = it.toContentState(null)
|
||||
if (it.isInvited) {
|
||||
// Get the inviteSender
|
||||
matrixClient.getRoomInfoFlow(roomId).first()
|
||||
.getOrNull()
|
||||
?.inviter
|
||||
?.toInviteSender()
|
||||
?.let { inviteSender ->
|
||||
value = it.toContentState(inviteSender)
|
||||
}
|
||||
}
|
||||
},
|
||||
onFailure = { throwable ->
|
||||
if (throwable.message?.contains("403") == true) {
|
||||
value = if (throwable.message?.contains("403") == true) {
|
||||
ContentState.UnknownRoom(roomIdOrAlias)
|
||||
} else {
|
||||
ContentState.Failure(roomIdOrAlias, throwable)
|
||||
@@ -118,7 +134,9 @@ class JoinRoomPresenter @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun RoomPreview.toContentState(): ContentState {
|
||||
private fun RoomPreview.toContentState(
|
||||
inviteSender: InviteSender?
|
||||
): ContentState {
|
||||
return ContentState.Loaded(
|
||||
roomId = roomId,
|
||||
name = name,
|
||||
@@ -128,7 +146,7 @@ private fun RoomPreview.toContentState(): ContentState {
|
||||
isDirect = false,
|
||||
roomAvatarUrl = avatarUrl,
|
||||
joinAuthorisationStatus = when {
|
||||
isInvited -> JoinAuthorisationStatus.IsInvited
|
||||
isInvited -> JoinAuthorisationStatus.IsInvited(inviteSender)
|
||||
canKnock -> JoinAuthorisationStatus.CanKnock
|
||||
isPublic -> JoinAuthorisationStatus.CanJoin
|
||||
else -> JoinAuthorisationStatus.Unknown
|
||||
@@ -165,7 +183,9 @@ internal fun MatrixRoomInfo.toContentState(): ContentState {
|
||||
isDirect = isDirect,
|
||||
roomAvatarUrl = avatarUrl,
|
||||
joinAuthorisationStatus = when {
|
||||
currentUserMembership == CurrentUserMembership.INVITED -> JoinAuthorisationStatus.IsInvited
|
||||
currentUserMembership == CurrentUserMembership.INVITED -> JoinAuthorisationStatus.IsInvited(
|
||||
inviteSender = inviter?.toInviteSender()
|
||||
)
|
||||
isPublic -> JoinAuthorisationStatus.CanJoin
|
||||
else -> JoinAuthorisationStatus.Unknown
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.ui.model.InviteSender
|
||||
|
||||
@Immutable
|
||||
data class JoinRoomState(
|
||||
@@ -71,9 +72,9 @@ sealed interface ContentState {
|
||||
}
|
||||
}
|
||||
|
||||
enum class JoinAuthorisationStatus {
|
||||
IsInvited,
|
||||
CanKnock,
|
||||
CanJoin,
|
||||
Unknown,
|
||||
sealed interface JoinAuthorisationStatus {
|
||||
data class IsInvited(val inviteSender: InviteSender?) : JoinAuthorisationStatus
|
||||
data object CanKnock : JoinAuthorisationStatus
|
||||
data object CanJoin : JoinAuthorisationStatus
|
||||
data object Unknown : JoinAuthorisationStatus
|
||||
}
|
||||
|
||||
@@ -19,10 +19,14 @@ package io.element.android.features.joinroom.impl
|
||||
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.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.ui.model.InviteSender
|
||||
|
||||
open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> {
|
||||
override val values: Sequence<JoinRoomState>
|
||||
@@ -48,7 +52,10 @@ open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> {
|
||||
)
|
||||
),
|
||||
aJoinRoomState(
|
||||
contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited)
|
||||
contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited(null))
|
||||
),
|
||||
aJoinRoomState(
|
||||
contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited(anInviteSender()))
|
||||
),
|
||||
aJoinRoomState(
|
||||
contentState = aFailureContentState()
|
||||
@@ -102,5 +109,15 @@ fun aJoinRoomState(
|
||||
eventSink = eventSink
|
||||
)
|
||||
|
||||
internal fun anInviteSender(
|
||||
userId: UserId = UserId("@bob:domain"),
|
||||
displayName: String = "Bob",
|
||||
avatarData: AvatarData = AvatarData(userId.value, displayName, size = AvatarSize.InviteSender),
|
||||
) = InviteSender(
|
||||
userId = userId,
|
||||
displayName = displayName,
|
||||
avatarData = avatarData,
|
||||
)
|
||||
|
||||
private val A_ROOM_ID = RoomId("!exa:matrix.org")
|
||||
private val A_ROOM_ALIAS = RoomAlias("#exa:matrix.org")
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
package io.element.android.features.joinroom.impl
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
@@ -47,6 +49,7 @@ 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.TopAppBar
|
||||
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.ui.components.InviteSenderView
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
@@ -103,7 +106,7 @@ private fun JoinRoomFooter(
|
||||
} else {
|
||||
val joinAuthorisationStatus = state.joinAuthorisationStatus
|
||||
when (joinAuthorisationStatus) {
|
||||
JoinAuthorisationStatus.IsInvited -> {
|
||||
is JoinAuthorisationStatus.IsInvited -> {
|
||||
ButtonRowMolecule(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(20.dp)) {
|
||||
OutlinedButton(
|
||||
text = stringResource(CommonStrings.action_decline),
|
||||
@@ -159,7 +162,16 @@ private fun JoinRoomContent(
|
||||
RoomPreviewTitleAtom(contentState.computedTitle)
|
||||
},
|
||||
subtitle = {
|
||||
RoomPreviewSubtitleAtom(contentState.computedSubtitle)
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
RoomPreviewSubtitleAtom(contentState.computedSubtitle)
|
||||
val inviteSender = (contentState.joinAuthorisationStatus as? JoinAuthorisationStatus.IsInvited)?.inviteSender
|
||||
if (inviteSender != null) {
|
||||
InviteSenderView(inviteSender = inviteSender)
|
||||
}
|
||||
}
|
||||
},
|
||||
description = {
|
||||
RoomPreviewDescriptionAtom(contentState.topic ?: "")
|
||||
|
||||
@@ -101,7 +101,7 @@ class JoinRoomPresenterTest {
|
||||
presenter.test {
|
||||
skipItems(1)
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.joinAuthorisationStatus).isEqualTo(JoinAuthorisationStatus.IsInvited)
|
||||
assertThat(state.joinAuthorisationStatus).isEqualTo(JoinAuthorisationStatus.IsInvited(null))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ class JoinRoomViewTest {
|
||||
val eventsRecorder = EventsRecorder<JoinRoomEvents>()
|
||||
rule.setJoinRoomView(
|
||||
aJoinRoomState(
|
||||
contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited),
|
||||
contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited(null)),
|
||||
eventSink = eventsRecorder,
|
||||
),
|
||||
)
|
||||
@@ -93,7 +93,7 @@ class JoinRoomViewTest {
|
||||
val eventsRecorder = EventsRecorder<JoinRoomEvents>()
|
||||
rule.setJoinRoomView(
|
||||
aJoinRoomState(
|
||||
contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited),
|
||||
contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited(null)),
|
||||
eventSink = eventsRecorder,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -66,7 +66,8 @@ import io.element.android.libraries.designsystem.theme.roomListRoomName
|
||||
import io.element.android.libraries.designsystem.theme.unreadIndicator
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.ui.components.InviteSender
|
||||
import io.element.android.libraries.matrix.ui.components.InviteSenderView
|
||||
import io.element.android.libraries.matrix.ui.model.InviteSender
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import timber.log.Timber
|
||||
|
||||
@@ -96,7 +97,10 @@ internal fun RoomSummaryRow(
|
||||
InviteSubtitle(isDirect = room.isDirect, inviteSender = room.inviteSender, canonicalAlias = room.canonicalAlias)
|
||||
if (!room.isDirect && room.inviteSender != null) {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
InviteSenderRow(sender = room.inviteSender)
|
||||
InviteSenderView(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
inviteSender = room.inviteSender,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
InviteButtonsRow(
|
||||
@@ -290,24 +294,6 @@ private fun InviteNameAndIndicatorRow(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InviteSenderRow(
|
||||
sender: InviteSender,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
) {
|
||||
Avatar(avatarData = sender.avatarData)
|
||||
Text(
|
||||
text = sender.annotatedString(),
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InviteButtonsRow(
|
||||
onAcceptClicked: () -> Unit,
|
||||
|
||||
@@ -26,7 +26,7 @@ import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter
|
||||
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.RoomSummary
|
||||
import io.element.android.libraries.matrix.ui.components.InviteSender
|
||||
import io.element.android.libraries.matrix.ui.model.toInviteSender
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomListRoomSummaryFactory @Inject constructor(
|
||||
@@ -83,18 +83,7 @@ class RoomListRoomSummaryFactory @Inject constructor(
|
||||
hasRoomCall = roomSummary.details.hasRoomCall,
|
||||
isDirect = roomSummary.details.isDirect,
|
||||
isFavorite = roomSummary.details.isFavorite,
|
||||
inviteSender = roomSummary.details.inviter?.run {
|
||||
InviteSender(
|
||||
userId = userId,
|
||||
displayName = displayName ?: "",
|
||||
avatarData = AvatarData(
|
||||
id = userId.value,
|
||||
name = displayName,
|
||||
url = avatarUrl,
|
||||
size = AvatarSize.InviteSender,
|
||||
),
|
||||
)
|
||||
},
|
||||
inviteSender = roomSummary.details.inviter?.toInviteSender(),
|
||||
isDm = roomSummary.details.isDm,
|
||||
canonicalAlias = roomSummary.details.canonicalAlias,
|
||||
displayType = if (roomSummary.details.currentUserMembership == CurrentUserMembership.INVITED) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.ui.components.InviteSender
|
||||
import io.element.android.libraries.matrix.ui.model.InviteSender
|
||||
|
||||
@Immutable
|
||||
data class RoomListRoomSummary(
|
||||
|
||||
@@ -23,7 +23,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.ui.components.InviteSender
|
||||
import io.element.android.libraries.matrix.ui.model.InviteSender
|
||||
|
||||
open class RoomListRoomSummaryProvider : PreviewParameterProvider<RoomListRoomSummary> {
|
||||
override val values: Sequence<RoomListRoomSummary>
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.libraries.matrix.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.ui.model.InviteSender
|
||||
|
||||
@Composable
|
||||
fun InviteSenderView(
|
||||
inviteSender: InviteSender,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
modifier = modifier,
|
||||
) {
|
||||
Avatar(avatarData = inviteSender.avatarData)
|
||||
Text(
|
||||
text = inviteSender.annotatedString(),
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun InviteSenderViewPreview() = ElementPreview {
|
||||
InviteSenderView(
|
||||
inviteSender = InviteSender(
|
||||
userId = UserId("@bob:example.com"),
|
||||
displayName = "Bob",
|
||||
avatarData = AvatarData(
|
||||
id = "@bob:example.com",
|
||||
name = "Bob",
|
||||
url = null,
|
||||
size = AvatarSize.InviteSender
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.ui.components
|
||||
package io.element.android.libraries.matrix.ui.model
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -25,7 +25,9 @@ import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.ui.R
|
||||
|
||||
@Immutable
|
||||
@@ -54,3 +56,14 @@ data class InviteSender(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun RoomMember.toInviteSender() = InviteSender(
|
||||
userId = userId,
|
||||
displayName = displayName ?: "",
|
||||
avatarData = AvatarData(
|
||||
id = userId.value,
|
||||
name = displayName,
|
||||
url = avatarUrl,
|
||||
size = AvatarSize.InviteSender,
|
||||
),
|
||||
)
|
||||
Reference in New Issue
Block a user