Display user status next to display names across rooms and profiles

This commit is contained in:
ganfra
2026-06-24 17:59:08 +02:00
parent 18034e02a2
commit 06a903718b
46 changed files with 386 additions and 89 deletions
@@ -26,6 +26,7 @@ import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.RoomNotificationSettings
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
import io.element.android.libraries.matrix.api.user.DisplayedStatus
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.components.aMatrixUserList
import kotlinx.collections.immutable.toImmutableList
@@ -75,6 +76,7 @@ fun aDmRoomMember(
role: RoomMember.Role = RoomMember.Role.User,
membershipChangeReason: String? = null,
isServiceMember: Boolean = false,
displayedStatus: DisplayedStatus? = null,
) = RoomMember(
userId = userId,
displayName = displayName,
@@ -86,6 +88,7 @@ fun aDmRoomMember(
role = role,
membershipChangeReason = membershipChangeReason,
isServiceMember = isServiceMember,
displayedStatus = displayedStatus,
)
fun aRoomDetailsState(
@@ -178,12 +181,13 @@ fun aDmRoomDetailsState(
roomName: String = "Daniel",
isEncrypted: Boolean = true,
dmRoomMemberVerificationState: UserProfileVerificationState = UserProfileVerificationState.UNKNOWN,
displayedStatus: DisplayedStatus? = null,
) = aRoomDetailsState(
roomName = roomName,
isPublic = false,
isEncrypted = isEncrypted,
canInvite = true,
roomType = RoomDetailsType.Dm(otherMember = aDmRoomMember(isIgnored = isDmMemberIgnored)),
roomType = RoomDetailsType.Dm(otherMember = aDmRoomMember(isIgnored = isDmMemberIgnored, displayedStatus = displayedStatus)),
dmOtherMemberDetailsState = aUserProfileState(
isBlocked = AsyncData.Success(isDmMemberIgnored),
verificationState = dmRoomMemberVerificationState,
@@ -37,6 +37,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import im.vector.app.features.analytics.plan.Interaction
@@ -88,6 +89,7 @@ import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.getBestName
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.model.getAvatarData
import io.element.android.libraries.matrix.ui.model.toText
import io.element.android.libraries.testtags.TestTags
import io.element.android.libraries.testtags.testTag
import io.element.android.libraries.ui.strings.CommonStrings
@@ -489,11 +491,23 @@ private fun RoomHeaderSection(
}
.testTag(TestTags.roomDetailAvatar)
)
TitleAndSubtitle(
title = roomName,
subtitle = roomAlias?.value,
onSubtitleClick = onSubtitleClick,
Spacer(modifier = Modifier.height(24.dp))
Text(
text = roomName,
style = ElementTheme.typography.fontHeadingLgBold,
textAlign = TextAlign.Center,
)
if (roomAlias != null) {
Spacer(modifier = Modifier.height(12.dp))
Text(
modifier = Modifier.niceClickable { onSubtitleClick(roomAlias.value) },
text = roomAlias.value,
style = ElementTheme.typography.fontBodyLgRegular,
color = ElementTheme.colors.textSecondary,
textAlign = TextAlign.Center,
)
}
Spacer(modifier = Modifier.height(12.dp))
}
}
@@ -531,37 +545,34 @@ private fun DmHeaderSection(
}
.testTag(TestTags.roomDetailAvatar)
)
TitleAndSubtitle(
title = roomName,
subtitle = otherMember.userId.value,
onSubtitleClick = onSubtitleClick,
)
}
}
@Composable
private fun TitleAndSubtitle(
title: String,
subtitle: String?,
onSubtitleClick: (String) -> Unit,
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Spacer(modifier = Modifier.height(24.dp))
Text(
text = title,
text = roomName,
style = ElementTheme.typography.fontHeadingLgBold,
textAlign = TextAlign.Center,
)
if (subtitle != null) {
Spacer(modifier = Modifier.height(6.dp))
val userStatus = otherMember.displayedStatus?.toText()
if(userStatus != null){
Spacer(modifier = Modifier.height(12.dp))
Text(
modifier = Modifier.niceClickable { onSubtitleClick(subtitle) },
text = subtitle,
style = ElementTheme.typography.fontBodyLgRegular,
text = userStatus,
style = ElementTheme.typography.fontBodyLgMedium,
maxLines = 1,
color = ElementTheme.colors.textSecondary,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
}
Spacer(modifier = Modifier.height(12.dp))
Text(
modifier = Modifier.niceClickable { onSubtitleClick(otherMember.userId.value) },
text = otherMember.userId.value,
style = ElementTheme.typography.fontBodyLgRegular,
color = ElementTheme.colors.textSecondary,
textAlign = TextAlign.Center,
)
Spacer(modifier = Modifier.height(12.dp))
}
}
@@ -28,6 +28,7 @@ import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.user.DisplayedStatus
import kotlinx.collections.immutable.persistentListOf
internal class RoomMemberListStateProvider : PreviewParameterProvider<RoomMemberListState> {
@@ -129,6 +130,7 @@ fun aRoomMember(
role: RoomMember.Role = RoomMember.Role.User,
membershipChangeReason: String? = null,
isServiceMember: Boolean = false,
displayedStatus: DisplayedStatus? = null,
) = RoomMember(
userId = userId,
displayName = displayName,
@@ -140,6 +142,7 @@ fun aRoomMember(
role = role,
membershipChangeReason = membershipChangeReason,
isServiceMember = isServiceMember,
displayedStatus = displayedStatus,
)
fun aRoomMemberList() = persistentListOf(
@@ -128,6 +128,7 @@ class RoomMemberDetailsPresenter(
return userProfileState.copy(
userName = roomUserName ?: userProfileState.userName,
avatarUrl = roomUserAvatar ?: userProfileState.avatarUrl,
displayedStatus = roomMember?.displayedStatus ?: userProfileState.displayedStatus,
verificationState = verificationState,
snackbarMessage = snackbarMessage,
eventSink = ::handleEvent,