Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle tapping on user mentions #2021

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/1448.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Tapping on a user mention pill opens their profile.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import io.element.android.libraries.di.SingleIn
import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.matrix.api.core.ProgressCallback
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.Mention
Expand Down Expand Up @@ -335,7 +336,7 @@ class MessageComposerPresenter @Inject constructor(
add(Mention.AtRoom)
}
for (userId in state.userIds) {
add(Mention.User(userId))
add(Mention.User(UserId(userId)))
}
}
}.orEmpty()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@
import androidx.constraintlayout.compose.ConstrainScope
import androidx.constraintlayout.compose.ConstraintLayout
import io.element.android.compound.theme.ElementTheme
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
import io.element.android.features.messages.impl.timeline.TimelineEvents
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
import io.element.android.features.messages.impl.timeline.components.event.TimelineItemEventContentView
import io.element.android.features.messages.impl.timeline.components.event.toExtraPadding
Expand Down Expand Up @@ -98,10 +98,10 @@
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.permalink.PermalinkData
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
import io.element.android.libraries.matrix.api.room.Mention
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnail
import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.coroutines.launch
import timber.log.Timber
import kotlin.math.abs
import kotlin.math.roundToInt

Expand Down Expand Up @@ -138,6 +138,13 @@
inReplyToClick(inReplyToEventId)
}

fun onMentionClicked(mention: Mention) {
when (mention) {

Check warning on line 142 in features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt

View check run for this annotation

Codecov / codecov/patch

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt#L142

Added line #L142 was not covered by tests
is Mention.User -> onUserDataClick(mention.userId)
else -> Unit // TODO implement actions for other mentions being clicked

Check warning on line 144 in features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt

View check run for this annotation

Codecov / codecov/patch

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt#L144

Added line #L144 was not covered by tests
}
}

Column(modifier = modifier.fillMaxWidth()) {
if (event.groupPosition.isNew()) {
Spacer(modifier = Modifier.height(16.dp))
Expand Down Expand Up @@ -182,6 +189,7 @@
onReactionClicked = { emoji -> onReactionClick(emoji, event) },
onReactionLongClicked = { emoji -> onReactionLongClick(emoji, event) },
onMoreReactionsClicked = { onMoreReactionsClick(event) },
onMentionClicked = ::onMentionClicked,
eventSink = eventSink,
)
}
Expand All @@ -200,6 +208,7 @@
onReactionClicked = { emoji -> onReactionClick(emoji, event) },
onReactionLongClicked = { emoji -> onReactionLongClick(emoji, event) },
onMoreReactionsClicked = { onMoreReactionsClick(event) },
onMentionClicked = ::onMentionClicked,
eventSink = eventSink,
)
}
Expand Down Expand Up @@ -254,6 +263,7 @@
onReactionClicked: (emoji: String) -> Unit,
onReactionLongClicked: (emoji: String) -> Unit,
onMoreReactionsClicked: (event: TimelineItem.Event) -> Unit,
onMentionClicked: (Mention) -> Unit,
eventSink: (TimelineEvents) -> Unit,
modifier: Modifier = Modifier,
) {
Expand Down Expand Up @@ -316,6 +326,7 @@
onTimestampClicked = {
onTimestampClicked(event)
},
onMentionClicked = onMentionClicked,
eventSink = eventSink,
)
}
Expand Down Expand Up @@ -387,6 +398,7 @@
onMessageLongClick: () -> Unit,
inReplyToClick: () -> Unit,
onTimestampClicked: () -> Unit,
onMentionClicked: (Mention) -> Unit,
eventSink: (TimelineEvents) -> Unit,
@SuppressLint("ModifierParameter")
@Suppress("ModifierNaming")
Expand Down Expand Up @@ -512,15 +524,17 @@
isMine = event.isMine,
isEditable = event.isEditable,
onLinkClicked = { url ->
Timber.d("Clicked on: $url")
when (PermalinkParser.parse(Uri.parse(url))) {
when (val permalink = PermalinkParser.parse(Uri.parse(url))) {

Check warning on line 527 in features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt

View check run for this annotation

Codecov / codecov/patch

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt#L527

Added line #L527 was not covered by tests
is PermalinkData.UserLink -> {
// TODO open member details
onMentionClicked(Mention.User(UserId(permalink.userId)))

Check warning on line 529 in features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt

View check run for this annotation

Codecov / codecov/patch

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt#L529

Added line #L529 was not covered by tests
}
is PermalinkData.RoomLink -> {
onMentionClicked(Mention.Room(permalink.getRoomId(), permalink.getRoomAlias()))

Check warning on line 532 in features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt

View check run for this annotation

Codecov / codecov/patch

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt#L532

Added line #L532 was not covered by tests
}
is PermalinkData.FallbackLink -> {
is PermalinkData.FallbackLink,
is PermalinkData.RoomEmailInviteLink -> {
context.openUrlInExternalApp(url)
}
else -> Unit // TODO handle other types of links, as room ones
}
},
extraPadding = event.toExtraPadding(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,7 @@ class MessageComposerPresenterTest {

advanceUntilIdle()

assertThat(room.sendMessageMentions).isEqualTo(listOf(Mention.User(A_USER_ID.value)))
assertThat(room.sendMessageMentions).isEqualTo(listOf(Mention.User(A_USER_ID)))

// Check intentional mentions on reply sent
initialState.eventSink(MessageComposerEvents.SetMode(aReplyMode()))
Expand All @@ -877,7 +877,7 @@ class MessageComposerPresenterTest {
initialState.eventSink(MessageComposerEvents.SendMessage(A_MESSAGE.toMessage()))
advanceUntilIdle()

assertThat(room.sendMessageMentions).isEqualTo(listOf(Mention.User(A_USER_ID_2.value)))
assertThat(room.sendMessageMentions).isEqualTo(listOf(Mention.User(A_USER_ID_2)))

// Check intentional mentions on edit message
skipItems(1)
Expand All @@ -893,7 +893,7 @@ class MessageComposerPresenterTest {
initialState.eventSink(MessageComposerEvents.SendMessage(A_MESSAGE.toMessage()))
advanceUntilIdle()

assertThat(room.sendMessageMentions).isEqualTo(listOf(Mention.User(A_USER_ID_3.value)))
assertThat(room.sendMessageMentions).isEqualTo(listOf(Mention.User(A_USER_ID_3)))

skipItems(1)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package io.element.android.libraries.matrix.api.permalink

import android.net.Uri
import androidx.compose.runtime.Immutable
import io.element.android.libraries.matrix.api.core.RoomId
import kotlinx.collections.immutable.ImmutableList

/**
Expand All @@ -32,7 +33,15 @@ sealed interface PermalinkData {
val isRoomAlias: Boolean,
val eventId: String?,
val viaParameters: ImmutableList<String>
) : PermalinkData
) : PermalinkData {
fun getRoomId(): RoomId? {
return roomIdOrAlias.takeIf { !isRoomAlias }?.let(::RoomId)
}

fun getRoomAlias(): String? {
return roomIdOrAlias.takeIf { isRoomAlias }
}
}

/*
* &room_name=Team2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@

package io.element.android.libraries.matrix.api.room

import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId

sealed interface Mention {
data class User(val userId: String): Mention
data class User(val userId: UserId): Mention
data object AtRoom: Mention
data class Room(val roomId: RoomId?, val roomAlias: String?): Mention

Check warning on line 25 in libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/Mention.kt

View check run for this annotation

Codecov / codecov/patch

libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/Mention.kt#L25

Added line #L25 was not covered by tests
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.element.android.libraries.matrix.api.permalink

import com.google.common.truth.Truth.assertThat
import kotlinx.collections.immutable.persistentListOf
import org.junit.Test

class PermalinkDataTest {

@Test
fun `getRoomId() returns value when isRoomAlias is false`() {
val permalinkData = PermalinkData.RoomLink(
roomIdOrAlias = "!abcdef123456:matrix.org",
isRoomAlias = false,
eventId = null,
viaParameters = persistentListOf(),
)
assertThat(permalinkData.getRoomId()).isNotNull()
assertThat(permalinkData.getRoomAlias()).isNull()
}

@Test
fun `getRoomAlias() returns value when isRoomAlias is true`() {
val permalinkData = PermalinkData.RoomLink(
roomIdOrAlias = "#room:matrix.org",
isRoomAlias = true,
eventId = null,
viaParameters = persistentListOf(),
)
assertThat(permalinkData.getRoomId()).isNull()
assertThat(permalinkData.getRoomAlias()).isNotNull()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ import org.matrix.rustcomponents.sdk.Mentions

fun List<Mention>.map(): Mentions {
val hasAtRoom = any { it is Mention.AtRoom }
val userIds = filterIsInstance<Mention.User>().map { it.userId }
val userIds = filterIsInstance<Mention.User>().map { it.userId.value }
return Mentions(userIds, hasAtRoom)
}
Loading