diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index 065c81e407..3e70e9c026 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -92,6 +92,7 @@ import io.element.android.libraries.matrix.ui.room.canRedactOwnAsState import io.element.android.libraries.matrix.ui.room.canSendMessageAsState import io.element.android.libraries.textcomposer.model.MessageComposerMode import io.element.android.libraries.ui.strings.CommonStrings +import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -151,6 +152,9 @@ class MessagesPresenter @AssistedInject constructor( val roomAvatar: AsyncData by remember { derivedStateOf { roomInfo?.avatarData()?.let { AsyncData.Success(it) } ?: AsyncData.Uninitialized } } + val heroes by remember { + derivedStateOf { roomInfo?.heroes().orEmpty().toPersistentList() } + } var hasDismissedInviteDialog by rememberSaveable { mutableStateOf(false) @@ -217,6 +221,7 @@ class MessagesPresenter @AssistedInject constructor( roomId = room.roomId, roomName = roomName, roomAvatar = roomAvatar, + heroes = heroes, userHasPermissionToSendMessage = userHasPermissionToSendMessage, userHasPermissionToRedactOwn = userHasPermissionToRedactOwn, userHasPermissionToRedactOther = userHasPermissionToRedactOther, @@ -250,6 +255,17 @@ class MessagesPresenter @AssistedInject constructor( ) } + private fun MatrixRoomInfo.heroes(): List { + return heroes.map { user -> + AvatarData( + id = user.userId.value, + name = user.displayName, + url = user.avatarUrl, + size = AvatarSize.TimelineRoom + ) + } + } + private fun CoroutineScope.handleTimelineAction( action: TimelineItemAction, targetEvent: TimelineItem.Event, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt index 752aa94a9f..e8657d70bd 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt @@ -29,12 +29,14 @@ import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.matrix.api.core.RoomId +import kotlinx.collections.immutable.ImmutableList @Immutable data class MessagesState( val roomId: RoomId, val roomName: AsyncData, val roomAvatar: AsyncData, + val heroes: ImmutableList, val userHasPermissionToSendMessage: Boolean, val userHasPermissionToRedactOwn: Boolean, val userHasPermissionToRedactOther: Boolean, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt index 526edfb1e7..1396d3e17c 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt @@ -99,8 +99,8 @@ fun aMessagesState( userHasPermissionToSendReaction: Boolean = true, composerState: MessageComposerState = aMessageComposerState( textEditorState = TextEditorState.Rich(aRichTextEditorState(initialText = "Hello", initialFocus = true)), - isFullScreen = false, - mode = MessageComposerMode.Normal, + isFullScreen = false, + mode = MessageComposerMode.Normal, ), voiceMessageComposerState: VoiceMessageComposerState = aVoiceMessageComposerState(), timelineState: TimelineState = aTimelineState( @@ -121,6 +121,7 @@ fun aMessagesState( roomId = RoomId("!id:domain"), roomName = roomName, roomAvatar = roomAvatar, + heroes = persistentListOf(), userHasPermissionToSendMessage = userHasPermissionToSendMessage, userHasPermissionToRedactOwn = userHasPermissionToRedactOwn, userHasPermissionToRedactOther = userHasPermissionToRedactOther, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt index b8997865ce..f28ff69905 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt @@ -83,9 +83,9 @@ import io.element.android.libraries.androidutils.ui.hideKeyboard import io.element.android.libraries.designsystem.atomic.molecules.IconTitlePlaceholdersRowMolecule import io.element.android.libraries.designsystem.components.ProgressDialog import io.element.android.libraries.designsystem.components.ProgressDialogType -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.components.avatar.CompositeAvatar import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog import io.element.android.libraries.designsystem.preview.ElementPreview @@ -187,6 +187,7 @@ fun MessagesView( MessagesViewTopBar( roomName = state.roomName.dataOrNull(), roomAvatar = state.roomAvatar.dataOrNull(), + heroes = state.heroes, callState = state.callState, onBackClick = { // Since the textfield is now based on an Android view, this is no longer done automatically. @@ -442,6 +443,7 @@ private fun MessagesViewComposerBottomSheetContents( private fun MessagesViewTopBar( roomName: String?, roomAvatar: AvatarData?, + heroes: List, callState: RoomCallState, onRoomDetailsClick: () -> Unit, onJoinCallClick: () -> Unit, @@ -457,6 +459,7 @@ private fun MessagesViewTopBar( RoomAvatarAndNameRow( roomName = roomName, roomAvatar = roomAvatar, + heroes = heroes, modifier = titleModifier ) } else { @@ -500,13 +503,17 @@ private fun CallMenuItem( private fun RoomAvatarAndNameRow( roomName: String, roomAvatar: AvatarData, + heroes: List, modifier: Modifier = Modifier ) { Row( modifier = modifier, verticalAlignment = Alignment.CenterVertically ) { - Avatar(roomAvatar) + CompositeAvatar( + avatarData = roomAvatar, + heroes = heroes, + ) Spacer(modifier = Modifier.width(8.dp)) Text( text = roomName, diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt index d90faef985..f7602faa16 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt @@ -53,7 +53,7 @@ import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryProvid import io.element.android.features.roomlist.impl.model.RoomSummaryDisplayType import io.element.android.libraries.core.extensions.orEmpty import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAtom -import io.element.android.libraries.designsystem.components.avatar.Avatar +import io.element.android.libraries.designsystem.components.avatar.CompositeAvatar import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button @@ -158,7 +158,10 @@ private fun RoomSummaryScaffoldRow( .padding(horizontal = 16.dp, vertical = 11.dp) .height(IntrinsicSize.Min), ) { - Avatar(room.avatarData) + CompositeAvatar( + avatarData = room.avatarData, + heroes = room.heroes, + ) Spacer(modifier = Modifier.width(16.dp)) Column( modifier = Modifier.fillMaxWidth(), diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt index 6ad7c07960..bf24dfd6dd 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt @@ -23,6 +23,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_NAME +import kotlinx.collections.immutable.toPersistentList import org.junit.Test class RoomListRoomSummaryTest { @@ -91,6 +92,7 @@ internal fun createRoomListRoomSummary( userDefinedNotificationMode: RoomNotificationMode? = null, isFavorite: Boolean = false, displayType: RoomSummaryDisplayType = RoomSummaryDisplayType.ROOM, + heroes: List = emptyList(), ) = RoomListRoomSummary( id = A_ROOM_ID.value, roomId = A_ROOM_ID, @@ -110,4 +112,5 @@ internal fun createRoomListRoomSummary( canonicalAlias = null, inviteSender = null, isDm = false, + heroes = heroes.toPersistentList(), )