Merge pull request #2027 from element-hq/feature/bma/openRoomAvatar

Feature/bma/open room avatar
This commit is contained in:
Benoit Marty 2023-12-14 16:00:34 +01:00 committed by GitHub
commit 82e0871ee8
7 changed files with 34 additions and 26 deletions

1
changelog.d/1918.misc Normal file
View file

@ -0,0 +1 @@
Add ability to see the room avatar in the media viewer.

View file

@ -242,7 +242,6 @@ class MessagesFlowNode @AssistedInject constructor(
backstack.push(navTarget) backstack.push(navTarget)
} }
is TimelineItemVideoContent -> { is TimelineItemVideoContent -> {
val mediaSource = event.content.videoSource
val navTarget = NavTarget.MediaViewer( val navTarget = NavTarget.MediaViewer(
mediaInfo = MediaInfo( mediaInfo = MediaInfo(
name = event.content.body, name = event.content.body,
@ -250,13 +249,12 @@ class MessagesFlowNode @AssistedInject constructor(
formattedFileSize = event.content.formattedFileSize, formattedFileSize = event.content.formattedFileSize,
fileExtension = event.content.fileExtension fileExtension = event.content.fileExtension
), ),
mediaSource = mediaSource, mediaSource = event.content.videoSource,
thumbnailSource = event.content.thumbnailSource, thumbnailSource = event.content.thumbnailSource,
) )
backstack.push(navTarget) backstack.push(navTarget)
} }
is TimelineItemFileContent -> { is TimelineItemFileContent -> {
val mediaSource = event.content.fileSource
val navTarget = NavTarget.MediaViewer( val navTarget = NavTarget.MediaViewer(
mediaInfo = MediaInfo( mediaInfo = MediaInfo(
name = event.content.body, name = event.content.body,
@ -264,13 +262,12 @@ class MessagesFlowNode @AssistedInject constructor(
formattedFileSize = event.content.formattedFileSize, formattedFileSize = event.content.formattedFileSize,
fileExtension = event.content.fileExtension fileExtension = event.content.fileExtension
), ),
mediaSource = mediaSource, mediaSource = event.content.fileSource,
thumbnailSource = event.content.thumbnailSource, thumbnailSource = event.content.thumbnailSource,
) )
backstack.push(navTarget) backstack.push(navTarget)
} }
is TimelineItemAudioContent -> { is TimelineItemAudioContent -> {
val mediaSource = event.content.mediaSource
val navTarget = NavTarget.MediaViewer( val navTarget = NavTarget.MediaViewer(
mediaInfo = MediaInfo( mediaInfo = MediaInfo(
name = event.content.body, name = event.content.body,
@ -278,7 +275,7 @@ class MessagesFlowNode @AssistedInject constructor(
formattedFileSize = event.content.formattedFileSize, formattedFileSize = event.content.formattedFileSize,
fileExtension = event.content.fileExtension fileExtension = event.content.fileExtension
), ),
mediaSource = mediaSource, mediaSource = event.content.mediaSource,
thumbnailSource = null, thumbnailSource = null,
) )
backstack.push(navTarget) backstack.push(navTarget)

View file

@ -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.invite.RoomInviteMembersNode
import io.element.android.features.roomdetails.impl.members.RoomMemberListNode 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.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.features.roomdetails.impl.notificationsettings.RoomNotificationSettingsNode
import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.BackstackNode
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
@ -87,7 +87,7 @@ class RoomDetailsFlowNode @AssistedInject constructor(
data class RoomMemberDetails(val roomMemberId: UserId) : NavTarget data class RoomMemberDetails(val roomMemberId: UserId) : NavTarget
@Parcelize @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 { override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
@ -110,8 +110,8 @@ class RoomDetailsFlowNode @AssistedInject constructor(
backstack.push(NavTarget.RoomNotificationSettings(showUserDefinedSettingStyle = false)) backstack.push(NavTarget.RoomNotificationSettings(showUserDefinedSettingStyle = false))
} }
override fun openAvatarPreview(username: String, url: String) { override fun openAvatarPreview(name: String, url: String) {
backstack.push(NavTarget.MemberAvatarPreview(username, url)) backstack.push(NavTarget.AvatarPreview(name, url))
} }
} }
createNode<RoomDetailsNode>(buildContext, listOf(roomDetailsCallback)) createNode<RoomDetailsNode>(buildContext, listOf(roomDetailsCallback))
@ -151,7 +151,7 @@ class RoomDetailsFlowNode @AssistedInject constructor(
is NavTarget.RoomMemberDetails -> { is NavTarget.RoomMemberDetails -> {
val callback = object : RoomMemberDetailsNode.Callback { val callback = object : RoomMemberDetailsNode.Callback {
override fun openAvatarPreview(username: String, avatarUrl: String) { override fun openAvatarPreview(username: String, avatarUrl: String) {
backstack.push(NavTarget.MemberAvatarPreview(username, avatarUrl)) backstack.push(NavTarget.AvatarPreview(username, avatarUrl))
} }
override fun onStartDM(roomId: RoomId) { override fun onStartDM(roomId: RoomId) {
@ -161,22 +161,22 @@ class RoomDetailsFlowNode @AssistedInject constructor(
val plugins = listOf(RoomMemberDetailsNode.RoomMemberDetailsInput(navTarget.roomMemberId), callback) val plugins = listOf(RoomMemberDetailsNode.RoomMemberDetailsInput(navTarget.roomMemberId), callback)
createNode<RoomMemberDetailsNode>(buildContext, plugins) createNode<RoomMemberDetailsNode>(buildContext, plugins)
} }
is NavTarget.MemberAvatarPreview -> { is NavTarget.AvatarPreview -> {
// We need to fake the MimeType here for the viewer to work. // We need to fake the MimeType here for the viewer to work.
val mimeType = MimeTypes.Images val mimeType = MimeTypes.Images
val input = MediaViewerNode.Inputs( val input = MediaViewerNode.Inputs(
mediaInfo = MediaInfo( mediaInfo = MediaInfo(
name = navTarget.userName, name = navTarget.name,
mimeType = mimeType, mimeType = mimeType,
formattedFileSize = "", formattedFileSize = "",
fileExtension = "" fileExtension = ""
), ),
mediaSource = MediaSource(url = navTarget.avatarUrl), mediaSource = MediaSource(url = navTarget.avatarUrl),
thumbnailSource = MediaSource(url = navTarget.avatarUrl), thumbnailSource = null,
canDownload = false, canDownload = false,
canShare = false, canShare = false,
) )
createNode<RoomMemberAvatarPreviewNode>(buildContext, listOf(input)) createNode<AvatarPreviewNode>(buildContext, listOf(input))
} }
} }
} }

View file

@ -52,7 +52,7 @@ class RoomDetailsNode @AssistedInject constructor(
fun openInviteMembers() fun openInviteMembers()
fun editRoomDetails() fun editRoomDetails()
fun openRoomNotificationSettings() fun openRoomNotificationSettings()
fun openAvatarPreview(username: String, url: String) fun openAvatarPreview(name: String, url: String)
} }
private val callbacks = plugins<Callback>() private val callbacks = plugins<Callback>()
@ -111,8 +111,8 @@ class RoomDetailsNode @AssistedInject constructor(
callbacks.forEach { it.editRoomDetails() } callbacks.forEach { it.editRoomDetails() }
} }
private fun openAvatarPreview(username: String, url: String) { private fun openAvatarPreview(name: String, url: String) {
callbacks.forEach { it.openAvatarPreview(username, url) } callbacks.forEach { it.openAvatarPreview(name, url) }
} }
@Composable @Composable

View file

@ -16,6 +16,7 @@
package io.element.android.features.roomdetails.impl package io.element.android.features.roomdetails.impl
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column 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.designsystem.utils.CommonDrawables
import io.element.android.libraries.matrix.api.room.RoomMember 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.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.getBestName
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
@Composable @Composable
@ -89,7 +91,7 @@ fun RoomDetailsView(
openRoomMemberList: () -> Unit, openRoomMemberList: () -> Unit,
openRoomNotificationSettings: () -> Unit, openRoomNotificationSettings: () -> Unit,
invitePeople: () -> Unit, invitePeople: () -> Unit,
openAvatarPreview: (username: String, url: String) -> Unit, openAvatarPreview: (name: String, url: String) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
fun onShareMember() { fun onShareMember() {
@ -120,7 +122,10 @@ fun RoomDetailsView(
avatarUrl = state.roomAvatarUrl, avatarUrl = state.roomAvatarUrl,
roomId = state.roomId, roomId = state.roomId,
roomName = state.roomName, roomName = state.roomName,
roomAlias = state.roomAlias roomAlias = state.roomAlias,
openAvatarPreview = { avatarUrl ->
openAvatarPreview(state.roomName, avatarUrl)
},
) )
MainActionsSection( MainActionsSection(
state = state, state = state,
@ -134,10 +139,8 @@ fun RoomDetailsView(
avatarUrl = state.roomAvatarUrl ?: member.avatarUrl, avatarUrl = state.roomAvatarUrl ?: member.avatarUrl,
userId = member.userId.value, userId = member.userId.value,
userName = state.roomName, userName = state.roomName,
openAvatarPreview = { openAvatarPreview = { avatarUrl ->
if (member.avatarUrl != null) { openAvatarPreview(member.getBestName(), avatarUrl)
openAvatarPreview(member.displayName ?: member.userId.value, member.avatarUrl!!)
}
}, },
) )
RoomMemberMainActionsSection(onShareUser = ::onShareMember) RoomMemberMainActionsSection(onShareUser = ::onShareMember)
@ -265,6 +268,7 @@ private fun RoomHeaderSection(
roomId: String, roomId: String,
roomName: String, roomName: String,
roomAlias: String?, roomAlias: String?,
openAvatarPreview: (url: String) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
Column( Column(
@ -275,7 +279,9 @@ private fun RoomHeaderSection(
) { ) {
Avatar( Avatar(
avatarData = AvatarData(roomId, roomName, avatarUrl, AvatarSize.RoomHeader), 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)) Spacer(modifier = Modifier.height(24.dp))
Text( Text(

View file

@ -26,7 +26,7 @@ import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerNode
import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerPresenter import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerPresenter
@ContributesNode(RoomScope::class) @ContributesNode(RoomScope::class)
class RoomMemberAvatarPreviewNode @AssistedInject constructor( class AvatarPreviewNode @AssistedInject constructor(
@Assisted buildContext: BuildContext, @Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>, @Assisted plugins: List<Plugin>,
presenterFactory: MediaViewerPresenter.Factory, presenterFactory: MediaViewerPresenter.Factory,

View file

@ -32,3 +32,7 @@ data class RoomMember(
enum class RoomMembershipState { enum class RoomMembershipState {
BAN, INVITE, JOIN, KNOCK, LEAVE BAN, INVITE, JOIN, KNOCK, LEAVE
} }
fun RoomMember.getBestName(): String {
return displayName?.takeIf { it.isNotEmpty() } ?: userId.value
}