diff --git a/changelog.d/8219.feature b/changelog.d/8219.feature new file mode 100644 index 0000000000..648bc7c624 --- /dev/null +++ b/changelog.d/8219.feature @@ -0,0 +1 @@ +Permalinks to a room/space are pillified diff --git a/changelog.d/8220.feature b/changelog.d/8220.feature new file mode 100644 index 0000000000..e7862bb5fe --- /dev/null +++ b/changelog.d/8220.feature @@ -0,0 +1 @@ +Permalinks to a matrix user are pillified diff --git a/changelog.d/8221.feature b/changelog.d/8221.feature new file mode 100644 index 0000000000..f542012bc1 --- /dev/null +++ b/changelog.d/8221.feature @@ -0,0 +1 @@ +Permalinks to messages are pillified diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 62f061f009..439479151c 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3539,4 +3539,11 @@ Access Token Your access token gives full access to your account. Do not share it with anyone. + + + Message from %s + Message + Message in %s + Message in room + Room/Space diff --git a/library/ui-styles/src/main/res/values/dimens.xml b/library/ui-styles/src/main/res/values/dimens.xml index 4c911c9e97..55cbddf78c 100644 --- a/library/ui-styles/src/main/res/values/dimens.xml +++ b/library/ui-styles/src/main/res/values/dimens.xml @@ -18,8 +18,8 @@ 0.75 - 16dp - 20dp + 20sp + 26sp 4dp 128dp diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt index bae4b06a05..2de95850b0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt @@ -65,27 +65,14 @@ object MatrixPatterns { private const val APP_BASE_REGEX = "https://[A-Z0-9.-]+\\.[A-Z]{2,}/[A-Z]{3,}/#/room/" const val SEP_REGEX = "/" - private const val LINK_TO_ROOM_ID_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX - private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID = LINK_TO_ROOM_ID_REGEXP.toRegex(RegexOption.IGNORE_CASE) - - private const val LINK_TO_ROOM_ALIAS_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX - private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS = LINK_TO_ROOM_ALIAS_REGEXP.toRegex(RegexOption.IGNORE_CASE) - - private const val LINK_TO_APP_ROOM_ID_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX - private val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID = LINK_TO_APP_ROOM_ID_REGEXP.toRegex(RegexOption.IGNORE_CASE) - - private const val LINK_TO_APP_ROOM_ALIAS_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX - private val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = LINK_TO_APP_ROOM_ALIAS_REGEXP.toRegex(RegexOption.IGNORE_CASE) + private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK = PERMALINK_BASE_REGEX.toRegex(RegexOption.IGNORE_CASE) + private val PATTERN_CONTAIN_APP_PERMALINK = APP_BASE_REGEX.toRegex(RegexOption.IGNORE_CASE) // ascii characters in the range \x20 (space) to \x7E (~) val ORDER_STRING_REGEX = "[ -~]+".toRegex() // list of patterns to find some matrix item. val MATRIX_PATTERNS = listOf( - PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID, - PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS, - PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID, - PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS, PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER, PATTERN_CONTAIN_MATRIX_ALIAS, PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER, @@ -146,6 +133,12 @@ object MatrixPatterns { return str != null && str matches PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER } + fun isPermalink(str: String?): Boolean { + return str != null && + (PATTERN_CONTAIN_MATRIX_TO_PERMALINK.containsMatchIn(str) || + PATTERN_CONTAIN_APP_PERMALINK.containsMatchIn(str)) + } + /** * Extract server name from a matrix id. * diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixLinkify.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixLinkify.kt index c428e40203..060b93ed0f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixLinkify.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixLinkify.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.api.session.permalinks import android.text.Spannable +import android.util.Patterns import org.matrix.android.sdk.api.MatrixPatterns /** @@ -44,22 +45,26 @@ object MatrixLinkify { } val text = spannable.toString() var hasMatch = false - for (pattern in MatrixPatterns.MATRIX_PATTERNS) { + for (pattern in listOf(Patterns.WEB_URL.toRegex()).plus(MatrixPatterns.MATRIX_PATTERNS)) { for (match in pattern.findAll(spannable)) { hasMatch = true val startPos = match.range.first if (startPos == 0 || text[startPos - 1] != '/') { val endPos = match.range.last + 1 var url = text.substring(match.range) - if (MatrixPatterns.isUserId(url) || + val isPermalink = MatrixPatterns.isPermalink(url) + if (isPermalink || + MatrixPatterns.isUserId(url) || MatrixPatterns.isRoomAlias(url) || MatrixPatterns.isRoomId(url) || MatrixPatterns.isGroupId(url) || MatrixPatterns.isEventId(url)) { - url = PermalinkService.MATRIX_TO_URL_BASE + url + if (!isPermalink) { + url = PermalinkService.MATRIX_TO_URL_BASE + url + } + val span = MatrixPermalinkSpan(url, callback) + spannable.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) } - val span = MatrixPermalinkSpan(url, callback) - spannable.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt index 974f1cfcbe..0fd96798c8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt @@ -76,7 +76,8 @@ sealed class MatrixItem( data class RoomItem( override val id: String, override val displayName: String? = null, - override val avatarUrl: String? = null + override val avatarUrl: String? = null, + val roomDisplayName: String? = null ) : MatrixItem(id, displayName, avatarUrl) { init { @@ -102,7 +103,8 @@ sealed class MatrixItem( data class RoomAliasItem( override val id: String, override val displayName: String? = null, - override val avatarUrl: String? = null + override val avatarUrl: String? = null, + val roomDisplayName: String? = null ) : MatrixItem(id, displayName, avatarUrl) { init { @@ -136,6 +138,8 @@ sealed class MatrixItem( val displayName = when (this) { // use the room display name for the notify everyone item is EveryoneInRoomItem -> roomDisplayName + is RoomItem -> roomDisplayName ?: displayName + is RoomAliasItem -> roomDisplayName ?: displayName else -> displayName } return (displayName?.takeIf { it.isNotBlank() } ?: id) diff --git a/vector/src/main/java/im/vector/app/features/displayname/Extension.kt b/vector/src/main/java/im/vector/app/features/displayname/Extension.kt index 71c1cbf27d..4069b41a0c 100644 --- a/vector/src/main/java/im/vector/app/features/displayname/Extension.kt +++ b/vector/src/main/java/im/vector/app/features/displayname/Extension.kt @@ -20,7 +20,7 @@ import org.matrix.android.sdk.api.util.MatrixItem fun MatrixItem.getBestName(): String { // Note: this code is copied from [DisplayNameResolver] in the SDK - return if (this is MatrixItem.RoomAliasItem) { + return if (this is MatrixItem.RoomAliasItem && displayName.isNullOrBlank()) { // Best name is the id, and we keep the displayName of the room for the case we need the first letter id } else { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt index 034ae52a46..06444e9816 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt @@ -163,7 +163,6 @@ import im.vector.app.features.home.room.detail.widget.RoomWidgetsBottomSheet import im.vector.app.features.home.room.threads.ThreadsManager import im.vector.app.features.home.room.threads.arguments.ThreadTimelineArgs import im.vector.app.features.html.EventHtmlRenderer -import im.vector.app.features.html.PillsPostProcessor import im.vector.app.features.invite.VectorInviteView import im.vector.app.features.location.LocationSharingMode import im.vector.app.features.location.toLocationData @@ -247,7 +246,6 @@ class TimelineFragment : @Inject lateinit var matrixItemColorProvider: MatrixItemColorProvider @Inject lateinit var imageContentRenderer: ImageContentRenderer @Inject lateinit var roomDetailPendingActionStore: RoomDetailPendingActionStore - @Inject lateinit var pillsPostProcessorFactory: PillsPostProcessor.Factory @Inject lateinit var callManager: WebRtcCallManager @Inject lateinit var audioMessagePlaybackTracker: AudioMessagePlaybackTracker @Inject lateinit var shareIntentHandler: ShareIntentHandler diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/render/EventTextRenderer.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/render/EventTextRenderer.kt index c46112f995..cc09ea0296 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/render/EventTextRenderer.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/render/EventTextRenderer.kt @@ -20,21 +20,30 @@ import android.content.Context import android.text.Spannable import android.text.SpannableStringBuilder import android.text.Spanned +import android.util.Patterns import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.glide.GlideApp import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.html.PillImageSpan +import org.matrix.android.sdk.api.MatrixPatterns +import org.matrix.android.sdk.api.session.getRoomSummary +import org.matrix.android.sdk.api.session.getUserOrDefault +import org.matrix.android.sdk.api.session.permalinks.PermalinkData +import org.matrix.android.sdk.api.session.permalinks.PermalinkParser import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.room.model.RoomType import org.matrix.android.sdk.api.util.MatrixItem +import org.matrix.android.sdk.api.util.toMatrixItem class EventTextRenderer @AssistedInject constructor( @Assisted private val roomId: String?, private val context: Context, private val avatarRenderer: AvatarRenderer, - private val activeSessionHolder: ActiveSessionHolder, + private val sessionHolder: ActiveSessionHolder, ) { @AssistedFactory @@ -46,7 +55,8 @@ class EventTextRenderer @AssistedInject constructor( * @param text the text to be rendered */ fun render(text: CharSequence): CharSequence { - return renderNotifyEveryone(text) + val formattedText = renderPermalinks(text) + return renderNotifyEveryone(formattedText) } private fun renderNotifyEveryone(text: CharSequence): CharSequence { @@ -59,8 +69,18 @@ class EventTextRenderer @AssistedInject constructor( } } + private fun renderPermalinks(text: CharSequence): CharSequence { + return if (roomId != null) { + SpannableStringBuilder(text).apply { + addPermalinksSpans(this) + } + } else { + text + } + } + private fun addNotifyEveryoneSpans(text: Spannable, roomId: String) { - val room: RoomSummary? = activeSessionHolder.getSafeActiveSession()?.roomService()?.getRoomSummary(roomId) + val room: RoomSummary? = sessionHolder.getSafeActiveSession()?.roomService()?.getRoomSummary(roomId) val matrixItem = MatrixItem.EveryoneInRoomItem( id = roomId, avatarUrl = room?.avatarUrl, @@ -76,6 +96,23 @@ class EventTextRenderer @AssistedInject constructor( } } + private fun addPermalinksSpans(text: Spannable) { + for (match in Patterns.WEB_URL.toRegex().findAll(text)) { + val url = text.substring(match.range) + val matrixItem = if (MatrixPatterns.isPermalink(url)) { + when (val permalinkData = PermalinkParser.parse(url)) { + is PermalinkData.UserLink -> permalinkData.toMatrixItem() + is PermalinkData.RoomLink -> permalinkData.toMatrixItem() + else -> null + } + } else null + + if (matrixItem != null) { + addPillSpan(text, createPillImageSpan(matrixItem), match.range.first, match.range.last + 1) + } + } + } + private fun createPillImageSpan(matrixItem: MatrixItem) = PillImageSpan(GlideApp.with(context), avatarRenderer, context, matrixItem) @@ -87,4 +124,46 @@ class EventTextRenderer @AssistedInject constructor( ) { renderedText.setSpan(pillSpan, startSpan, endSpan, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) } + + private fun PermalinkData.UserLink.toMatrixItem(): MatrixItem? = + roomId?.let { sessionHolder.getSafeActiveSession()?.roomService()?.getRoomMember(userId, it)?.toMatrixItem() } + ?: sessionHolder.getSafeActiveSession()?.getUserOrDefault(userId)?.toMatrixItem() + + private fun PermalinkData.RoomLink.toMatrixItem(): MatrixItem = + if (eventId.isNullOrEmpty()) { + val room: RoomSummary? = sessionHolder.getSafeActiveSession()?.getRoomSummary(roomIdOrAlias) + when { + isRoomAlias -> MatrixItem.RoomAliasItem(roomIdOrAlias, room?.displayName, room?.avatarUrl) + room == null -> MatrixItem.RoomItem(roomIdOrAlias, context.getString(R.string.pill_message_unknown_room_or_space)) + room.roomType == RoomType.SPACE -> MatrixItem.SpaceItem(roomIdOrAlias, room.displayName, room.avatarUrl) + else -> MatrixItem.RoomItem(roomIdOrAlias, room.displayName, room.avatarUrl) + } + } else { + if (roomIdOrAlias == roomId) { + val session = sessionHolder.getSafeActiveSession() + val event = session?.eventService()?.getEventFromCache(roomId, eventId!!) + val user = event?.senderId?.let { session.roomService().getRoomMember(it, roomId) } + val text = user?.let { + context.getString(R.string.pill_message_from_user, user.displayName) + } ?: context.getString(R.string.pill_message_from_unknown_user) + MatrixItem.RoomItem(roomIdOrAlias, text, user?.avatarUrl, user?.displayName) + } else { + val room: RoomSummary? = sessionHolder.getSafeActiveSession()?.getRoomSummary(roomIdOrAlias) + when { + isRoomAlias -> MatrixItem.RoomAliasItem( + roomIdOrAlias, + context.getString(R.string.pill_message_in_room, room?.displayName ?: roomIdOrAlias), + room?.avatarUrl, + room?.displayName + ) + room != null -> MatrixItem.RoomItem( + roomIdOrAlias, + context.getString(R.string.pill_message_in_room, room.displayName), + room.avatarUrl, + room.displayName + ) + else -> MatrixItem.RoomItem(roomIdOrAlias, context.getString(R.string.pill_message_in_unknown_room)) + } + } + } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/tools/EventRenderingTools.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/tools/EventRenderingTools.kt index 3226b56c24..75babe9d64 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/tools/EventRenderingTools.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/tools/EventRenderingTools.kt @@ -44,12 +44,11 @@ fun CharSequence.findPillsAndProcess(scope: CoroutineScope, processBlock: (PillI } fun CharSequence.linkify(callback: TimelineEventController.UrlClickCallback?): CharSequence { - val text = this.toString() // SpannableStringBuilder is used to avoid Epoxy throwing ImmutableModelException val spannable = SpannableStringBuilder(this) MatrixLinkify.addLinks(spannable, object : MatrixPermalinkSpan.Callback { override fun onUrlClicked(url: String) { - callback?.onUrlClicked(url, text) + callback?.onUrlClicked(url, this.toString()) } }) VectorLinkify.addLinks(spannable, true) diff --git a/vector/src/main/java/im/vector/app/features/html/PillImageSpan.kt b/vector/src/main/java/im/vector/app/features/html/PillImageSpan.kt index b285bef9ec..af1bcb866f 100644 --- a/vector/src/main/java/im/vector/app/features/html/PillImageSpan.kt +++ b/vector/src/main/java/im/vector/app/features/html/PillImageSpan.kt @@ -26,14 +26,17 @@ import android.graphics.drawable.Drawable import android.text.style.ReplacementSpan import android.widget.TextView import androidx.annotation.UiThread +import androidx.core.content.ContextCompat import com.bumptech.glide.request.target.SimpleTarget import com.bumptech.glide.request.transition.Transition import com.google.android.material.chip.ChipDrawable import im.vector.app.R +import im.vector.app.core.extensions.isMatrixId import im.vector.app.core.glide.GlideRequests import im.vector.app.features.displayname.getBestName import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.themes.ThemeUtils +import org.matrix.android.sdk.api.extensions.orTrue import org.matrix.android.sdk.api.session.room.send.MatrixItemSpan import org.matrix.android.sdk.api.util.MatrixItem import java.lang.ref.WeakReference @@ -111,10 +114,28 @@ class PillImageSpan( private fun createChipDrawable(): ChipDrawable { val textPadding = context.resources.getDimension(R.dimen.pill_text_padding) - val icon = try { - avatarRenderer.getCachedDrawable(glideRequests, matrixItem) - } catch (exception: Exception) { - avatarRenderer.getPlaceholderDrawable(matrixItem) + val icon = when { + matrixItem is MatrixItem.RoomAliasItem && matrixItem.avatarUrl.isNullOrEmpty() && + matrixItem.displayName == context.getString(R.string.pill_message_in_room, matrixItem.id) -> { + ContextCompat.getDrawable(context, R.drawable.ic_permalink_round) + } + matrixItem is MatrixItem.RoomItem && matrixItem.avatarUrl.isNullOrEmpty() && ( + matrixItem.displayName == context.getString(R.string.pill_message_in_unknown_room) || + matrixItem.displayName == context.getString(R.string.pill_message_unknown_room_or_space) || + matrixItem.displayName == context.getString(R.string.pill_message_from_unknown_user) + ) -> { + ContextCompat.getDrawable(context, R.drawable.ic_permalink_round) + } + matrixItem is MatrixItem.UserItem && matrixItem.avatarUrl.isNullOrEmpty() && matrixItem.displayName?.isMatrixId().orTrue() -> { + ContextCompat.getDrawable(context, R.drawable.ic_user_round) + } + else -> { + try { + avatarRenderer.getCachedDrawable(glideRequests, matrixItem) + } catch (exception: Exception) { + avatarRenderer.getPlaceholderDrawable(matrixItem) + } + } } return ChipDrawable.createFromResource(context, R.xml.pill_view).apply { diff --git a/vector/src/main/java/im/vector/app/features/html/PillsPostProcessor.kt b/vector/src/main/java/im/vector/app/features/html/PillsPostProcessor.kt index f6e10a6df9..6b23d68e80 100644 --- a/vector/src/main/java/im/vector/app/features/html/PillsPostProcessor.kt +++ b/vector/src/main/java/im/vector/app/features/html/PillsPostProcessor.kt @@ -27,7 +27,7 @@ import im.vector.app.core.glide.GlideApp import im.vector.app.features.home.AvatarRenderer import io.noties.markwon.core.spans.LinkSpan import org.matrix.android.sdk.api.session.getRoomSummary -import org.matrix.android.sdk.api.session.getUserOrDefault +import org.matrix.android.sdk.api.session.getUser import org.matrix.android.sdk.api.session.permalinks.PermalinkData import org.matrix.android.sdk.api.session.permalinks.PermalinkParser import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -56,15 +56,15 @@ class PillsPostProcessor @AssistedInject constructor( * ========================================================================================== */ override fun afterRender(renderedText: Spannable) { - addPillSpans(renderedText, roomId) + addPillSpans(renderedText) } /* ========================================================================================== * Helper methods * ========================================================================================== */ - private fun addPillSpans(renderedText: Spannable, roomId: String?) { - addLinkSpans(renderedText, roomId) + private fun addPillSpans(renderedText: Spannable) { + addLinkSpans(renderedText) } private fun addPillSpan( @@ -76,11 +76,11 @@ class PillsPostProcessor @AssistedInject constructor( renderedText.setSpan(pillSpan, startSpan, endSpan, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) } - private fun addLinkSpans(renderedText: Spannable, roomId: String?) { + private fun addLinkSpans(renderedText: Spannable) { // We let markdown handle links and then we add PillImageSpan if needed. val linkSpans = renderedText.getSpans(0, renderedText.length, LinkSpan::class.java) linkSpans.forEach { linkSpan -> - val pillSpan = linkSpan.createPillSpan(roomId) ?: return@forEach + val pillSpan = linkSpan.createPillSpan() ?: return@forEach val startSpan = renderedText.getSpanStart(linkSpan) val endSpan = renderedText.getSpanEnd(linkSpan) // GlideImagesPlugin causes duplicated pills if we have a nested spans in the pill span, @@ -104,21 +104,18 @@ class PillsPostProcessor @AssistedInject constructor( private fun createPillImageSpan(matrixItem: MatrixItem) = PillImageSpan(GlideApp.with(context), avatarRenderer, context, matrixItem) - private fun LinkSpan.createPillSpan(roomId: String?): PillImageSpan? { + private fun LinkSpan.createPillSpan(): PillImageSpan? { val matrixItem = when (val permalinkData = PermalinkParser.parse(url)) { - is PermalinkData.UserLink -> permalinkData.toMatrixItem(roomId) + is PermalinkData.UserLink -> permalinkData.toMatrixItem() is PermalinkData.RoomLink -> permalinkData.toMatrixItem() else -> null } ?: return null return createPillImageSpan(matrixItem) } - private fun PermalinkData.UserLink.toMatrixItem(roomId: String?): MatrixItem? = - if (roomId == null) { - sessionHolder.getSafeActiveSession()?.getUserOrDefault(userId)?.toMatrixItem() - } else { - sessionHolder.getSafeActiveSession()?.roomService()?.getRoomMember(userId, roomId)?.toMatrixItem() - } + private fun PermalinkData.UserLink.toMatrixItem(): MatrixItem? = + roomId?.let { sessionHolder.getSafeActiveSession()?.roomService()?.getRoomMember(userId, it)?.toMatrixItem() } + ?: sessionHolder.getSafeActiveSession()?.getUser(userId)?.toMatrixItem() private fun PermalinkData.RoomLink.toMatrixItem(): MatrixItem? = if (eventId == null) { diff --git a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt index 18b9f03444..304bfa6d43 100644 --- a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt +++ b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt @@ -110,13 +110,8 @@ class PermalinkHandler @Inject constructor( val rootThreadEventId = permalinkData.eventId?.let { eventId -> val room = roomId?.let { session?.getRoom(it) } - - val rootThreadEventId = room?.getTimelineEvent(eventId)?.root?.getRootThreadEventId() - rootThreadEventId ?: if (room?.getTimelineEvent(eventId)?.isRootThread() == true) { - eventId - } else { - null - } + val event = room?.getTimelineEvent(eventId) + event?.root?.getRootThreadEventId() ?: eventId.takeIf { event?.isRootThread() == true } } openRoom( navigationInterceptor, diff --git a/vector/src/main/res/drawable/ic_permalink_round.xml b/vector/src/main/res/drawable/ic_permalink_round.xml new file mode 100644 index 0000000000..b63209017f --- /dev/null +++ b/vector/src/main/res/drawable/ic_permalink_round.xml @@ -0,0 +1,15 @@ + + + + diff --git a/vector/src/main/res/drawable/ic_user_round.xml b/vector/src/main/res/drawable/ic_user_round.xml index 721f3aa81c..5e0f2b417f 100644 --- a/vector/src/main/res/drawable/ic_user_round.xml +++ b/vector/src/main/res/drawable/ic_user_round.xml @@ -4,15 +4,15 @@ android:viewportWidth="24" android:viewportHeight="24"> + android:pathData="M18.709,21.951L19.564,23.216L18.709,21.951ZM4.8,21.601L3.883,22.822H3.883L4.8,21.601ZM18.676,18.899L19.738,19.996L20.478,19.28L20.092,18.325L18.676,18.899ZM5.324,18.899L3.908,18.325L3.522,19.28L4.262,19.996L5.324,18.899ZM12,25.527C14.8,25.527 17.404,24.675 19.564,23.216L17.854,20.685C16.184,21.814 14.171,22.473 12,22.473V25.527ZM3.883,22.822C6.144,24.52 8.956,25.527 12,25.527V22.473C9.641,22.473 7.467,21.694 5.717,20.38L3.883,22.822ZM-1.527,12C-1.527,16.427 0.601,20.357 3.883,22.822L5.717,20.38C3.17,18.466 1.527,15.425 1.527,12H-1.527ZM12,-1.527C4.529,-1.527 -1.527,4.529 -1.527,12H1.527C1.527,6.216 6.216,1.527 12,1.527V-1.527ZM25.527,12C25.527,4.529 19.471,-1.527 12,-1.527V1.527C17.784,1.527 22.473,6.216 22.473,12H25.527ZM19.564,23.216C23.159,20.788 25.527,16.671 25.527,12H22.473C22.473,15.613 20.644,18.8 17.854,20.685L19.564,23.216ZM14.073,8.7C14.073,10.128 13.032,11.073 12,11.073V14.127C14.944,14.127 17.127,11.58 17.127,8.7H14.073ZM12,6.327C13.032,6.327 14.073,7.272 14.073,8.7H17.127C17.127,5.82 14.944,3.273 12,3.273V6.327ZM9.927,8.7C9.927,7.272 10.968,6.327 12,6.327V3.273C9.055,3.273 6.873,5.82 6.873,8.7H9.927ZM12,11.073C10.968,11.073 9.927,10.128 9.927,8.7H6.873C6.873,11.58 9.055,14.127 12,14.127V11.073ZM17.614,17.801C16.16,19.209 14.182,20.073 12,20.073V23.127C15.007,23.127 17.737,21.933 19.738,19.996L17.614,17.801ZM12,15.927C14.378,15.927 16.417,17.391 17.26,19.472L20.092,18.325C18.798,15.131 15.664,12.873 12,12.873V15.927ZM6.74,19.472C7.582,17.391 9.622,15.927 12,15.927V12.873C8.336,12.873 5.202,15.131 3.908,18.325L6.74,19.472ZM12,20.073C9.818,20.073 7.84,19.209 6.386,17.801L4.262,19.996C6.263,21.933 8.993,23.127 12,23.127V20.073Z" + android:fillColor="?vctr_content_secondary"/>