Click on avatar in moderation bottom sheet opens avatar preview (#6991)
* Make the avatar in the room member moderation bottom sheet open the avatar in the media viewer (#6962) * Make the avatar in the room member moderation bottom sheet open the avatar in the media viewer. * Fix issue with avatar overlay not dismissing the bottom sheet: the bottom sheet would eat all the touch events until the first click, which would somehow cancel this behaviour * Fix lint issues * Update screenshots --------- Co-authored-by: bxdxnn <267911624+bxdxnn@users.noreply.github.com> Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
committed by
GitHub
parent
786c53ac06
commit
bea2903093
+36
@@ -190,6 +190,9 @@ class MessagesFlowNode(
|
||||
|
||||
@Parcelize
|
||||
data object ThreadsList : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data class AvatarPreview(val name: String, val avatarUrl: String) : NavTarget
|
||||
}
|
||||
|
||||
private val callback: MessagesEntryPoint.Callback = callback()
|
||||
@@ -327,6 +330,10 @@ class MessagesFlowNode(
|
||||
override fun navigateToDeveloperSettings() {
|
||||
callback.navigateToDeveloperSettings()
|
||||
}
|
||||
|
||||
override fun navigateToAvatarPreview(username: String, avatarUrl: String) {
|
||||
overlay.show(NavTarget.AvatarPreview(username, avatarUrl))
|
||||
}
|
||||
}
|
||||
val inputs = MessagesNode.Inputs(focusedEventId = navTarget.focusedEventId)
|
||||
createNode<MessagesNode>(buildContext, listOf(callback, inputs))
|
||||
@@ -562,6 +569,10 @@ class MessagesFlowNode(
|
||||
override fun navigateToDeveloperSettings() {
|
||||
callback.navigateToDeveloperSettings()
|
||||
}
|
||||
|
||||
override fun navigateToAvatarPreview(username: String, avatarUrl: String) {
|
||||
overlay.show(NavTarget.AvatarPreview(username, avatarUrl))
|
||||
}
|
||||
}
|
||||
createNode<ThreadedMessagesNode>(buildContext, listOf(inputs, callback))
|
||||
}
|
||||
@@ -573,6 +584,31 @@ class MessagesFlowNode(
|
||||
}
|
||||
createNode<ThreadsListNode>(buildContext, listOf(callback))
|
||||
}
|
||||
is NavTarget.AvatarPreview -> {
|
||||
val callback = object : MediaViewerEntryPoint.Callback {
|
||||
override fun onDone() {
|
||||
overlay.hide()
|
||||
}
|
||||
|
||||
override fun viewInTimeline(eventId: EventId) {
|
||||
// Cannot happen
|
||||
}
|
||||
|
||||
override fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) {
|
||||
// Cannot happen
|
||||
}
|
||||
}
|
||||
val params = mediaViewerEntryPoint.createParamsForAvatar(
|
||||
filename = navTarget.name,
|
||||
avatarUrl = navTarget.avatarUrl,
|
||||
)
|
||||
mediaViewerEntryPoint.createNode(
|
||||
parentNode = this,
|
||||
buildContext = buildContext,
|
||||
params = params,
|
||||
callback = callback,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -66,6 +66,7 @@ import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.alias.matches
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||
import io.element.android.libraries.mediaplayer.api.MediaPlayer
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.libraries.ui.utils.a11y.hasExternalKeyboard
|
||||
@@ -136,6 +137,8 @@ class MessagesNode(
|
||||
fun navigateToDeveloperSettings()
|
||||
|
||||
fun navigateToThreadsList()
|
||||
|
||||
fun navigateToAvatarPreview(username: String, avatarUrl: String)
|
||||
}
|
||||
|
||||
override fun onBuilt() {
|
||||
@@ -319,6 +322,11 @@ class MessagesNode(
|
||||
else -> state.roomMemberModerationState.eventSink(RoomMemberModerationEvents.ProcessAction(action, target))
|
||||
}
|
||||
},
|
||||
onAvatarClick = { user ->
|
||||
user.avatarUrl?.let { url ->
|
||||
callback.navigateToAvatarPreview(user.getBestName(), url)
|
||||
}
|
||||
},
|
||||
modifier = Modifier,
|
||||
)
|
||||
|
||||
|
||||
+8
@@ -67,6 +67,7 @@ import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.alias.matches
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||
import io.element.android.libraries.ui.utils.a11y.hasExternalKeyboard
|
||||
import io.element.android.libraries.ui.utils.a11y.isTalkbackActive
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
@@ -138,6 +139,8 @@ class ThreadedMessagesNode(
|
||||
fun navigateToRoomCall(roomId: RoomId, isAudioCall: Boolean)
|
||||
fun navigateToThread(threadRootId: ThreadId, focusedEventId: EventId?)
|
||||
fun navigateToDeveloperSettings()
|
||||
|
||||
fun navigateToAvatarPreview(username: String, avatarUrl: String)
|
||||
}
|
||||
|
||||
override fun onBuilt() {
|
||||
@@ -315,6 +318,11 @@ class ThreadedMessagesNode(
|
||||
else -> state.roomMemberModerationState.eventSink(RoomMemberModerationEvents.ProcessAction(action, target))
|
||||
}
|
||||
},
|
||||
onAvatarClick = { user ->
|
||||
user.avatarUrl?.let { url ->
|
||||
callback.navigateToAvatarPreview(user.getBestName(), url)
|
||||
}
|
||||
},
|
||||
modifier = Modifier,
|
||||
)
|
||||
|
||||
|
||||
+4
@@ -258,6 +258,10 @@ class RoomDetailsFlowNode(
|
||||
override fun navigateToInviteMembers() {
|
||||
backstack.push(NavTarget.InviteMembers)
|
||||
}
|
||||
|
||||
override fun navigateToAvatarPreview(username: String, avatarUrl: String) {
|
||||
overlay.show(NavTarget.AvatarPreview(username, avatarUrl))
|
||||
}
|
||||
}
|
||||
createNode<RoomMemberListNode>(buildContext, listOf(roomMemberListCallback))
|
||||
}
|
||||
|
||||
+7
@@ -27,6 +27,7 @@ import io.element.android.libraries.architecture.appyx.launchMolecule
|
||||
import io.element.android.libraries.architecture.callback
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
|
||||
@ContributesNode(RoomScope::class)
|
||||
@@ -41,6 +42,7 @@ class RoomMemberListNode(
|
||||
interface Callback : Plugin {
|
||||
fun navigateToRoomMemberDetails(roomMemberId: UserId)
|
||||
fun navigateToInviteMembers()
|
||||
fun navigateToAvatarPreview(username: String, avatarUrl: String)
|
||||
}
|
||||
|
||||
private val callback: Callback = callback()
|
||||
@@ -82,6 +84,11 @@ class RoomMemberListNode(
|
||||
else -> state.moderationState.eventSink(RoomMemberModerationEvents.ProcessAction(action, target))
|
||||
}
|
||||
},
|
||||
onAvatarClick = { user ->
|
||||
user.avatarUrl?.let { url ->
|
||||
callback.navigateToAvatarPreview(user.getBestName(), url)
|
||||
}
|
||||
},
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
|
||||
+1
@@ -17,6 +17,7 @@ interface RoomMemberModerationRenderer {
|
||||
fun Render(
|
||||
state: RoomMemberModerationState,
|
||||
onSelectAction: (ModerationAction, MatrixUser) -> Unit,
|
||||
onAvatarClick: ((MatrixUser) -> Unit)?,
|
||||
modifier: Modifier,
|
||||
)
|
||||
}
|
||||
|
||||
+2
-1
@@ -25,10 +25,11 @@ class DefaultRoomMemberModerationRenderer : RoomMemberModerationRenderer {
|
||||
override fun Render(
|
||||
state: RoomMemberModerationState,
|
||||
onSelectAction: (ModerationAction, MatrixUser) -> Unit,
|
||||
onAvatarClick: ((MatrixUser) -> Unit)?,
|
||||
modifier: Modifier
|
||||
) {
|
||||
if (state is InternalRoomMemberModerationState) {
|
||||
RoomMemberModerationView(state, onSelectAction, modifier)
|
||||
RoomMemberModerationView(modifier = modifier, state = state, onSelectAction = onSelectAction, onAvatarClick = onAvatarClick)
|
||||
} else {
|
||||
SideEffect {
|
||||
Timber.d("RoomMemberModerationRenderer: Render called with unsupported state: $state")
|
||||
|
||||
+17
-10
@@ -12,6 +12,7 @@ import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
@@ -64,6 +65,7 @@ import timber.log.Timber
|
||||
fun RoomMemberModerationView(
|
||||
state: InternalRoomMemberModerationState,
|
||||
onSelectAction: (ModerationAction, MatrixUser) -> Unit,
|
||||
onAvatarClick: ((MatrixUser) -> Unit)?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
@@ -73,6 +75,7 @@ fun RoomMemberModerationView(
|
||||
user = selectedUser,
|
||||
actions = state.actions,
|
||||
onSelectAction = onSelectAction,
|
||||
onAvatarClick = onAvatarClick,
|
||||
onDismiss = { state.eventSink(InternalRoomMemberModerationEvents.Reset) },
|
||||
)
|
||||
}
|
||||
@@ -214,6 +217,7 @@ private fun RoomMemberActionsBottomSheet(
|
||||
user: MatrixUser,
|
||||
actions: ImmutableList<ModerationActionState>,
|
||||
onSelectAction: (ModerationAction, MatrixUser) -> Unit,
|
||||
onAvatarClick: ((MatrixUser) -> Unit)? = null,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
@@ -240,10 +244,11 @@ private fun RoomMemberActionsBottomSheet(
|
||||
modifier = Modifier
|
||||
.padding(bottom = 24.dp)
|
||||
.align(Alignment.CenterHorizontally)
|
||||
.clickable {
|
||||
.clickable(enabled = user.avatarUrl != null && onAvatarClick != null) {
|
||||
coroutineScope.launch {
|
||||
onSelectAction(ModerationAction.DisplayProfile, user)
|
||||
bottomSheetState.hide()
|
||||
onAvatarClick?.invoke(user)
|
||||
onDismiss()
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -282,8 +287,8 @@ private fun RoomMemberActionsBottomSheet(
|
||||
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.UserProfile())),
|
||||
onClick = {
|
||||
coroutineScope.launch {
|
||||
onSelectAction(action, user)
|
||||
bottomSheetState.hide()
|
||||
onSelectAction(action, user)
|
||||
}
|
||||
},
|
||||
enabled = actionState.isEnabled
|
||||
@@ -340,16 +345,18 @@ private fun RoomMemberActionsBottomSheet(
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun RoomMemberModerationViewPreview(@PreviewParameter(InternalRoomMemberModerationStateProvider::class) state: InternalRoomMemberModerationState) {
|
||||
val isDoingAction = listOf(state.kickUserAsyncAction, state.banUserAsyncAction, state.unbanUserAsyncAction).any { it is AsyncAction.Loading }
|
||||
val modifier = if (isDoingAction) {
|
||||
Modifier.fillMaxWidth().heightIn(min = 64.dp)
|
||||
} else {
|
||||
Modifier.fillMaxSize()
|
||||
}
|
||||
ElementPreview {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = 64.dp)
|
||||
) {
|
||||
Box(modifier) {
|
||||
RoomMemberModerationView(
|
||||
state = state,
|
||||
onSelectAction = { _, _ ->
|
||||
},
|
||||
onSelectAction = { _, _ -> },
|
||||
onAvatarClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8b15da251ba8ac26c61fd21079f09e3b614fd20e8ded4805cda0da180631afcc
|
||||
size 17347
|
||||
oid sha256:75880628a454ca00a186e5d1c5438117e7af4ab9b23eb6fbf9c9696210234169
|
||||
size 17246
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fc4a3ba905c3599ad8f6451787906ba61f8dc716464d81e8c1c1bc86023032c3
|
||||
size 20345
|
||||
oid sha256:1fe61c20e2c6a7bb72e82aefd546469dfc49bf736b6d12f4c1927628df1bdb3e
|
||||
size 20211
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5704d02932451bc129ec92f3a9dab7fd66bb55bfdf3e142a4f3a436ad1d3b129
|
||||
size 22722
|
||||
oid sha256:ca3ee9a09bbbc69f2ba7e8b40cdc5196cc53745fe3222282d98bcf948dc16745
|
||||
size 22596
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8755fa3568186a798047a7fbf05404c0f738b168ca77f16afecc815bbec084ab
|
||||
size 22828
|
||||
oid sha256:96971a8981aea8918c01827403933c9e75275a2fda92716f803e6f28ad284bae
|
||||
size 22702
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e611504d154db3889c1a5900e6af392ca058462450d66f0dde762ab4a45e1b76
|
||||
size 29532
|
||||
oid sha256:06ca0aa653033b59313325ad508c5916e2fedf29ba6dd3a5f714e90d01f4bf7c
|
||||
size 29644
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f6135b24d94d7732342ec9353cdefb115ce5e9a799dfaee5d57b2e8e0a7ed631
|
||||
size 26505
|
||||
oid sha256:ebfb75986cd385e9837a24a5f279e07f0744bab5613fd7cbaf0a493d021c7699
|
||||
size 26606
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7bf31df95e781eae5530ed98ab9773f3e7d0f4fd4152226596b78328b88d69a8
|
||||
size 27223
|
||||
oid sha256:a58e6ed7f10d7014c9c3b55fbb769e04619313212449a8fc582501d2904d669f
|
||||
size 27315
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ba469dd7ffb3b27261cc4f227584b7cc03bf2ddcb974a4a1150c9515a075ac78
|
||||
size 16562
|
||||
oid sha256:bc96eec2d61713f01d43c92812bbf27bc44a202ce55f0fa1dc8e8659dabcfcf2
|
||||
size 16347
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d21c293e519e998d8820171766f1651d2440b18dad6f002c6580ca3fe2f24d69
|
||||
size 19397
|
||||
oid sha256:56c4df7da32b71dca109a1db1f4a797a2930e3b42c00eb51d72f0e1f5b99bf48
|
||||
size 19200
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:24a1a6004dc058573f264a5f02ffc85ca925e9f0c01f7ceacbaf972b3335d327
|
||||
size 21819
|
||||
oid sha256:592c6ec197b193803679eee5df7769fa4858fe883a2f3a1294f39ad87f9f4ff1
|
||||
size 21610
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cf93cbb2ce344639162524714d254c0db21cab448dec38ee1d4820265678a7ec
|
||||
size 21909
|
||||
oid sha256:62e99b8070a394ea5b2d666f3a8abf0fe41ea4a34a382223903f2de4085195dc
|
||||
size 21710
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:641f434040dfc9f040622fd0f17519d353f0bc45a17603ef837e53fad2b529c2
|
||||
size 27570
|
||||
oid sha256:793cff43740f6e477a255af566985d8bb7b0242d89484b3f0fc5cfec3b4a2af8
|
||||
size 27608
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2d9c0f0c69bd55b5c9a925cb89587d959998a833c5927873b4ef358959ce4ece
|
||||
size 24944
|
||||
oid sha256:ad842be0c519bfd7713eb93df2a7216d159970aff1ea44725641c5db26f3ad6b
|
||||
size 24995
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f17c5df90399b6de382af8111ba36b0ec072596f42103f76477692a801493799
|
||||
size 25515
|
||||
oid sha256:541b9ad607838fc9d44d6d3759d61df54c178257fe646366304d96ebda5f7e77
|
||||
size 25565
|
||||
|
||||
Reference in New Issue
Block a user