diff --git a/changelog.d/1918.misc b/changelog.d/1918.misc new file mode 100644 index 0000000000..d850c133f8 --- /dev/null +++ b/changelog.d/1918.misc @@ -0,0 +1 @@ +Add ability to see the room avatar in the media viewer. diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index 7957eb2200..cc9ded778b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -242,7 +242,6 @@ class MessagesFlowNode @AssistedInject constructor( backstack.push(navTarget) } is TimelineItemVideoContent -> { - val mediaSource = event.content.videoSource val navTarget = NavTarget.MediaViewer( mediaInfo = MediaInfo( name = event.content.body, @@ -250,13 +249,12 @@ class MessagesFlowNode @AssistedInject constructor( formattedFileSize = event.content.formattedFileSize, fileExtension = event.content.fileExtension ), - mediaSource = mediaSource, + mediaSource = event.content.videoSource, thumbnailSource = event.content.thumbnailSource, ) backstack.push(navTarget) } is TimelineItemFileContent -> { - val mediaSource = event.content.fileSource val navTarget = NavTarget.MediaViewer( mediaInfo = MediaInfo( name = event.content.body, @@ -264,13 +262,12 @@ class MessagesFlowNode @AssistedInject constructor( formattedFileSize = event.content.formattedFileSize, fileExtension = event.content.fileExtension ), - mediaSource = mediaSource, + mediaSource = event.content.fileSource, thumbnailSource = event.content.thumbnailSource, ) backstack.push(navTarget) } is TimelineItemAudioContent -> { - val mediaSource = event.content.mediaSource val navTarget = NavTarget.MediaViewer( mediaInfo = MediaInfo( name = event.content.body, @@ -278,7 +275,7 @@ class MessagesFlowNode @AssistedInject constructor( formattedFileSize = event.content.formattedFileSize, fileExtension = event.content.fileExtension ), - mediaSource = mediaSource, + mediaSource = event.content.mediaSource, thumbnailSource = null, ) backstack.push(navTarget) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt index 27ddf47f92..36de25c270 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt @@ -34,7 +34,7 @@ import io.element.android.features.roomdetails.impl.edit.RoomDetailsEditNode import io.element.android.features.roomdetails.impl.invite.RoomInviteMembersNode import io.element.android.features.roomdetails.impl.members.RoomMemberListNode import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsNode -import io.element.android.features.roomdetails.impl.members.details.avatar.RoomMemberAvatarPreviewNode +import io.element.android.features.roomdetails.impl.members.details.avatar.AvatarPreviewNode import io.element.android.features.roomdetails.impl.notificationsettings.RoomNotificationSettingsNode import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler @@ -87,7 +87,7 @@ class RoomDetailsFlowNode @AssistedInject constructor( data class RoomMemberDetails(val roomMemberId: UserId) : NavTarget @Parcelize - data class MemberAvatarPreview(val userName: String, val avatarUrl: String) : NavTarget + data class AvatarPreview(val name: String, val avatarUrl: String) : NavTarget } override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { @@ -110,8 +110,8 @@ class RoomDetailsFlowNode @AssistedInject constructor( backstack.push(NavTarget.RoomNotificationSettings(showUserDefinedSettingStyle = false)) } - override fun openAvatarPreview(username: String, url: String) { - backstack.push(NavTarget.MemberAvatarPreview(username, url)) + override fun openAvatarPreview(name: String, url: String) { + backstack.push(NavTarget.AvatarPreview(name, url)) } } createNode(buildContext, listOf(roomDetailsCallback)) @@ -151,7 +151,7 @@ class RoomDetailsFlowNode @AssistedInject constructor( is NavTarget.RoomMemberDetails -> { val callback = object : RoomMemberDetailsNode.Callback { override fun openAvatarPreview(username: String, avatarUrl: String) { - backstack.push(NavTarget.MemberAvatarPreview(username, avatarUrl)) + backstack.push(NavTarget.AvatarPreview(username, avatarUrl)) } override fun onStartDM(roomId: RoomId) { @@ -161,22 +161,22 @@ class RoomDetailsFlowNode @AssistedInject constructor( val plugins = listOf(RoomMemberDetailsNode.RoomMemberDetailsInput(navTarget.roomMemberId), callback) createNode(buildContext, plugins) } - is NavTarget.MemberAvatarPreview -> { + is NavTarget.AvatarPreview -> { // We need to fake the MimeType here for the viewer to work. val mimeType = MimeTypes.Images val input = MediaViewerNode.Inputs( mediaInfo = MediaInfo( - name = navTarget.userName, + name = navTarget.name, mimeType = mimeType, formattedFileSize = "", fileExtension = "" ), mediaSource = MediaSource(url = navTarget.avatarUrl), - thumbnailSource = MediaSource(url = navTarget.avatarUrl), + thumbnailSource = null, canDownload = false, canShare = false, ) - createNode(buildContext, listOf(input)) + createNode(buildContext, listOf(input)) } } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt index f3fa9e2645..c656aa4449 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt @@ -52,7 +52,7 @@ class RoomDetailsNode @AssistedInject constructor( fun openInviteMembers() fun editRoomDetails() fun openRoomNotificationSettings() - fun openAvatarPreview(username: String, url: String) + fun openAvatarPreview(name: String, url: String) } private val callbacks = plugins() @@ -111,8 +111,8 @@ class RoomDetailsNode @AssistedInject constructor( callbacks.forEach { it.editRoomDetails() } } - private fun openAvatarPreview(username: String, url: String) { - callbacks.forEach { it.openAvatarPreview(username, url) } + private fun openAvatarPreview(name: String, url: String) { + callbacks.forEach { it.openAvatarPreview(name, url) } } @Composable diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt index 9c7151d4af..66455daf90 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt @@ -16,6 +16,7 @@ package io.element.android.features.roomdetails.impl +import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -77,6 +78,7 @@ import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.utils.CommonDrawables import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomNotificationMode +import io.element.android.libraries.matrix.api.room.getBestName import io.element.android.libraries.ui.strings.CommonStrings @Composable @@ -89,7 +91,7 @@ fun RoomDetailsView( openRoomMemberList: () -> Unit, openRoomNotificationSettings: () -> Unit, invitePeople: () -> Unit, - openAvatarPreview: (username: String, url: String) -> Unit, + openAvatarPreview: (name: String, url: String) -> Unit, modifier: Modifier = Modifier, ) { fun onShareMember() { @@ -120,7 +122,10 @@ fun RoomDetailsView( avatarUrl = state.roomAvatarUrl, roomId = state.roomId, roomName = state.roomName, - roomAlias = state.roomAlias + roomAlias = state.roomAlias, + openAvatarPreview = { avatarUrl -> + openAvatarPreview(state.roomName, avatarUrl) + }, ) MainActionsSection( state = state, @@ -134,10 +139,8 @@ fun RoomDetailsView( avatarUrl = state.roomAvatarUrl ?: member.avatarUrl, userId = member.userId.value, userName = state.roomName, - openAvatarPreview = { - if (member.avatarUrl != null) { - openAvatarPreview(member.displayName ?: member.userId.value, member.avatarUrl!!) - } + openAvatarPreview = { avatarUrl -> + openAvatarPreview(member.getBestName(), avatarUrl) }, ) RoomMemberMainActionsSection(onShareUser = ::onShareMember) @@ -265,6 +268,7 @@ private fun RoomHeaderSection( roomId: String, roomName: String, roomAlias: String?, + openAvatarPreview: (url: String) -> Unit, modifier: Modifier = Modifier ) { Column( @@ -275,7 +279,9 @@ private fun RoomHeaderSection( ) { Avatar( avatarData = AvatarData(roomId, roomName, avatarUrl, AvatarSize.RoomHeader), - modifier = Modifier.size(70.dp) + modifier = Modifier + .size(70.dp) + .clickable(enabled = avatarUrl != null) { openAvatarPreview(avatarUrl!!) } ) Spacer(modifier = Modifier.height(24.dp)) Text( diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/avatar/RoomMemberAvatarPreviewNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/avatar/AvatarPreviewNode.kt similarity index 95% rename from features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/avatar/RoomMemberAvatarPreviewNode.kt rename to features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/avatar/AvatarPreviewNode.kt index 8d186ae96c..ecd2806b88 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/avatar/RoomMemberAvatarPreviewNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/avatar/AvatarPreviewNode.kt @@ -26,7 +26,7 @@ import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerNode import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerPresenter @ContributesNode(RoomScope::class) -class RoomMemberAvatarPreviewNode @AssistedInject constructor( +class AvatarPreviewNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, presenterFactory: MediaViewerPresenter.Factory, diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt index 3c9bd030b0..54c00572c5 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt @@ -32,3 +32,7 @@ data class RoomMember( enum class RoomMembershipState { BAN, INVITE, JOIN, KNOCK, LEAVE } + +fun RoomMember.getBestName(): String { + return displayName?.takeIf { it.isNotEmpty() } ?: userId.value +}