Merge pull request #2027 from element-hq/feature/bma/openRoomAvatar
Feature/bma/open room avatar
This commit is contained in:
commit
82e0871ee8
7 changed files with 34 additions and 26 deletions
1
changelog.d/1918.misc
Normal file
1
changelog.d/1918.misc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Add ability to see the room avatar in the media viewer.
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue