Display user status next to display names across rooms and profiles

This commit is contained in:
ganfra
2026-06-24 17:59:08 +02:00
parent 18034e02a2
commit 06a903718b
46 changed files with 386 additions and 89 deletions
@@ -39,11 +39,17 @@ class MentionSpan(
private var typeface: Typeface = Typeface.DEFAULT
private var measuredTextWidth = 0
private var measuredTrailingWidth = 0
// The formatted display text, will be set by the formatter
var displayText: CharSequence = ""
private set
var trailingText: String? = null
set(value) {
field = value?.let { " $it" }
}
/**
* Updates the visual properties of this span.
*/
@@ -80,6 +86,10 @@ class MentionSpan(
displayText = formatter.formatDisplayText(type)
}
fun updateTrailingText(trailingText: String?){
this.trailingText = trailingText
}
override fun getSize(
paint: Paint,
text: CharSequence?,
@@ -91,7 +101,8 @@ class MentionSpan(
textPaint.typeface = typeface
// Measure the full text width without truncation
measuredTextWidth = textPaint.measureText(displayText, 0, displayText.length).roundToInt()
return measuredTextWidth + startPadding + endPadding
measuredTrailingWidth = trailingText?.let { textPaint.measureText(it).roundToInt() } ?: 0
return measuredTextWidth + measuredTrailingWidth + startPadding + endPadding
}
override fun draw(
@@ -106,7 +117,8 @@ class MentionSpan(
paint: Paint
) {
val availableWidth = (canvas.width - x).coerceAtLeast(0f)
val measuredWidth = measuredTextWidth + startPadding + endPadding
val measuredWidth = measuredTextWidth + measuredTrailingWidth + startPadding + endPadding
val pillWidth = minOf(availableWidth, measuredWidth.toFloat())
backgroundPaint.color = backgroundColor
@@ -118,18 +130,18 @@ class MentionSpan(
textPaint.color = textColor
textPaint.typeface = typeface
val availableWidthForText = availableWidth - startPadding - endPadding
val availableWidthForText = availableWidth - startPadding - endPadding - measuredTrailingWidth
val textToDraw = if (measuredTextWidth > availableWidthForText) {
TextUtils.ellipsize(
displayText,
textPaint,
availableWidthForText,
TextUtils.TruncateAt.END
)
TextUtils.ellipsize(displayText, textPaint, availableWidthForText, TextUtils.TruncateAt.END)
} else {
displayText
}
canvas.drawText(textToDraw, 0, textToDraw.length, x + startPadding, y.toFloat(), textPaint)
trailingText?.let {
val drawnTextWidth = minOf(availableWidthForText, measuredTextWidth.toFloat())
canvas.drawText(it, x + startPadding + drawnTextWidth, y.toFloat(), textPaint)
}
}
}
@@ -18,6 +18,7 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.matrix.ui.messages.RoomMemberProfilesCache
import io.element.android.libraries.matrix.ui.messages.RoomNamesCache
import io.element.android.libraries.matrix.ui.model.toEmojiText
interface MentionSpanUpdater {
fun updateMentionSpans(text: CharSequence): CharSequence
@@ -48,6 +49,13 @@ class DefaultMentionSpanUpdater(
for (mentionSpan in text.getMentionSpans()) {
mentionSpan.updateTheme(theme)
mentionSpan.updateDisplayText(formatter)
mentionSpan.updateTrailingText(
if (mentionSpan.type is MentionType.User) {
roomMemberProfilesCache.getDisplayedStatus(mentionSpan.type.userId)?.toEmojiText()
} else {
null
}
)
}
return text
}