Format state Event: use disambiguated Display name #2722.
- Rename some parameter and val from `senderDisplayName` (and consort) to `senderDisambiguatedDisplayName`. - In `InReplyToDetails`, replace `senderDisplayName` and `senderAvatarUrl` by `senderProfile`.
This commit is contained in:
parent
e0d40ec0a4
commit
03abfcaadb
29 changed files with 157 additions and 140 deletions
|
|
@ -269,9 +269,9 @@ private fun MessageSummary(event: TimelineItem.Event, modifier: Modifier = Modif
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Column(modifier = Modifier.weight(1f)) {
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
Row {
|
Row {
|
||||||
if (event.senderDisplayName != null) {
|
if (event.senderDisambiguatedDisplayName != null) {
|
||||||
Text(
|
Text(
|
||||||
text = event.senderDisplayName,
|
text = event.senderDisambiguatedDisplayName,
|
||||||
style = ElementTheme.typography.fontBodySmMedium,
|
style = ElementTheme.typography.fontBodySmMedium,
|
||||||
color = MaterialTheme.colorScheme.primary
|
color = MaterialTheme.colorScheme.primary
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ internal fun aTimelineItemEvent(
|
||||||
transactionId: TransactionId? = null,
|
transactionId: TransactionId? = null,
|
||||||
isMine: Boolean = false,
|
isMine: Boolean = false,
|
||||||
isEditable: Boolean = false,
|
isEditable: Boolean = false,
|
||||||
senderDisplayName: String = "Sender",
|
senderDisambiguatedDisplayName: String = "Sender",
|
||||||
content: TimelineItemEventContent = aTimelineItemTextContent(),
|
content: TimelineItemEventContent = aTimelineItemTextContent(),
|
||||||
groupPosition: TimelineItemGroupPosition = TimelineItemGroupPosition.None,
|
groupPosition: TimelineItemGroupPosition = TimelineItemGroupPosition.None,
|
||||||
sendState: LocalEventSendState? = null,
|
sendState: LocalEventSendState? = null,
|
||||||
|
|
@ -152,7 +152,7 @@ internal fun aTimelineItemEvent(
|
||||||
sentTime = "12:34",
|
sentTime = "12:34",
|
||||||
isMine = isMine,
|
isMine = isMine,
|
||||||
isEditable = isEditable,
|
isEditable = isEditable,
|
||||||
senderDisplayName = senderDisplayName,
|
senderDisambiguatedDisplayName = senderDisambiguatedDisplayName,
|
||||||
groupPosition = groupPosition,
|
groupPosition = groupPosition,
|
||||||
localSendState = sendState,
|
localSendState = sendState,
|
||||||
inReplyTo = inReplyTo,
|
inReplyTo = inReplyTo,
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
|
||||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnail
|
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnail
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
@ -561,10 +562,10 @@ private fun MessageEventBubbleContent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val inReplyTo = @Composable { inReplyTo: InReplyToDetails ->
|
val inReplyTo = @Composable { inReplyTo: InReplyToDetails ->
|
||||||
val senderName = inReplyTo.senderDisplayName ?: inReplyTo.senderId.value
|
val senderDisambiguatedDisplayName = inReplyTo.senderProfile.getDisambiguatedDisplayName(inReplyTo.senderId)
|
||||||
val topPadding = if (showThreadDecoration) 0.dp else 8.dp
|
val topPadding = if (showThreadDecoration) 0.dp else 8.dp
|
||||||
ReplyToContent(
|
ReplyToContent(
|
||||||
senderName = senderName,
|
senderDisambiguatedDisplayName = senderDisambiguatedDisplayName,
|
||||||
metadata = inReplyTo.metadata(),
|
metadata = inReplyTo.metadata(),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(top = topPadding, start = 8.dp, end = 8.dp)
|
.padding(top = topPadding, start = 8.dp, end = 8.dp)
|
||||||
|
|
@ -609,7 +610,7 @@ private fun MessageEventBubbleContent(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ReplyToContent(
|
private fun ReplyToContent(
|
||||||
senderName: String,
|
senderDisambiguatedDisplayName: String,
|
||||||
metadata: InReplyToMetadata?,
|
metadata: InReplyToMetadata?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
|
@ -633,13 +634,13 @@ private fun ReplyToContent(
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
}
|
}
|
||||||
val a11InReplyToText = stringResource(CommonStrings.common_in_reply_to, senderName)
|
val a11InReplyToText = stringResource(CommonStrings.common_in_reply_to, senderDisambiguatedDisplayName)
|
||||||
Column(verticalArrangement = Arrangement.SpaceBetween) {
|
Column(verticalArrangement = Arrangement.SpaceBetween) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.semantics {
|
modifier = Modifier.semantics {
|
||||||
contentDescription = a11InReplyToText
|
contentDescription = a11InReplyToText
|
||||||
},
|
},
|
||||||
text = senderName,
|
text = senderDisambiguatedDisplayName,
|
||||||
style = ElementTheme.typography.fontBodySmMedium,
|
style = ElementTheme.typography.fontBodySmMedium,
|
||||||
textAlign = TextAlign.Start,
|
textAlign = TextAlign.Start,
|
||||||
color = ElementTheme.materialColors.primary,
|
color = ElementTheme.materialColors.primary,
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
internal fun TimelineItemEventRowLongSenderNamePreview() = ElementPreviewLight {
|
internal fun TimelineItemEventRowLongSenderNamePreview() = ElementPreviewLight {
|
||||||
ATimelineItemEventRow(
|
ATimelineItemEventRow(
|
||||||
event = aTimelineItemEvent(
|
event = aTimelineItemEvent(
|
||||||
senderDisplayName = "a long sender display name to test single line and ellipsis at the end of the line",
|
senderDisambiguatedDisplayName = "a long sender display name to test single line and ellipsis at the end of the line",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ internal fun TimelineItemEventRowTimestampPreview(
|
||||||
body = str,
|
body = str,
|
||||||
),
|
),
|
||||||
reactionsState = aTimelineItemReactions(count = 0),
|
reactionsState = aTimelineItemReactions(count = 0),
|
||||||
senderDisplayName = "A sender",
|
senderDisambiguatedDisplayName = "A sender",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.MessageConten
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||||
|
|
@ -167,8 +168,11 @@ open class InReplyToDetailsProvider : PreviewParameterProvider<InReplyToDetails>
|
||||||
eventId = EventId("\$event"),
|
eventId = EventId("\$event"),
|
||||||
eventContent = eventContent,
|
eventContent = eventContent,
|
||||||
senderId = UserId("@Sender:domain"),
|
senderId = UserId("@Sender:domain"),
|
||||||
senderDisplayName = "Sender",
|
senderProfile = ProfileTimelineDetails.Ready(
|
||||||
senderAvatarUrl = null,
|
displayName = "Sender",
|
||||||
|
displayNameAmbiguous = false,
|
||||||
|
avatarUrl = null,
|
||||||
|
),
|
||||||
textContent = (eventContent as? MessageContent)?.body.orEmpty(),
|
textContent = (eventContent as? MessageContent)?.body.orEmpty(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,12 @@ class TimelineItemContentFactory @Inject constructor(
|
||||||
is FailedToParseMessageLikeContent -> failedToParseMessageFactory.create(itemContent)
|
is FailedToParseMessageLikeContent -> failedToParseMessageFactory.create(itemContent)
|
||||||
is FailedToParseStateContent -> failedToParseStateFactory.create(itemContent)
|
is FailedToParseStateContent -> failedToParseStateFactory.create(itemContent)
|
||||||
is MessageContent -> {
|
is MessageContent -> {
|
||||||
val senderDisplayName = eventTimelineItem.senderProfile.getDisambiguatedDisplayName(eventTimelineItem.sender)
|
val senderDisambiguatedDisplayName = eventTimelineItem.senderProfile.getDisambiguatedDisplayName(eventTimelineItem.sender)
|
||||||
messageFactory.create(itemContent, senderDisplayName, eventTimelineItem.eventId)
|
messageFactory.create(
|
||||||
|
content = itemContent,
|
||||||
|
senderDisambiguatedDisplayName = senderDisambiguatedDisplayName,
|
||||||
|
eventId = eventTimelineItem.eventId,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is ProfileChangeContent -> profileChangeFactory.create(eventTimelineItem)
|
is ProfileChangeContent -> profileChangeFactory.create(eventTimelineItem)
|
||||||
is RedactedContent -> redactedMessageFactory.create(itemContent)
|
is RedactedContent -> redactedMessageFactory.create(itemContent)
|
||||||
|
|
|
||||||
|
|
@ -70,17 +70,21 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||||
private val htmlConverterProvider: HtmlConverterProvider,
|
private val htmlConverterProvider: HtmlConverterProvider,
|
||||||
private val permalinkParser: PermalinkParser,
|
private val permalinkParser: PermalinkParser,
|
||||||
) {
|
) {
|
||||||
suspend fun create(content: MessageContent, senderDisplayName: String, eventId: EventId?): TimelineItemEventContent {
|
suspend fun create(
|
||||||
|
content: MessageContent,
|
||||||
|
senderDisambiguatedDisplayName: String,
|
||||||
|
eventId: EventId?,
|
||||||
|
): TimelineItemEventContent {
|
||||||
return when (val messageType = content.type) {
|
return when (val messageType = content.type) {
|
||||||
is EmoteMessageType -> {
|
is EmoteMessageType -> {
|
||||||
val emoteBody = "* $senderDisplayName ${messageType.body.trimEnd()}"
|
val emoteBody = "* $senderDisambiguatedDisplayName ${messageType.body.trimEnd()}"
|
||||||
TimelineItemEmoteContent(
|
TimelineItemEmoteContent(
|
||||||
body = emoteBody,
|
body = emoteBody,
|
||||||
htmlDocument = messageType.formatted?.toHtmlDocument(
|
htmlDocument = messageType.formatted?.toHtmlDocument(
|
||||||
permalinkParser = permalinkParser,
|
permalinkParser = permalinkParser,
|
||||||
prefix = "* $senderDisplayName",
|
prefix = "* $senderDisambiguatedDisplayName",
|
||||||
),
|
),
|
||||||
formattedBody = parseHtml(messageType.formatted, prefix = "* $senderDisplayName") ?: emoteBody.withLinks(),
|
formattedBody = parseHtml(messageType.formatted, prefix = "* $senderDisambiguatedDisplayName") ?: emoteBody.withLinks(),
|
||||||
isEdited = content.isEdited,
|
isEdited = content.isEdited,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,14 +55,14 @@ class TimelineItemEventFactory @Inject constructor(
|
||||||
val currentSender = currentTimelineItem.event.sender
|
val currentSender = currentTimelineItem.event.sender
|
||||||
val groupPosition =
|
val groupPosition =
|
||||||
computeGroupPosition(currentTimelineItem, timelineItems, index)
|
computeGroupPosition(currentTimelineItem, timelineItems, index)
|
||||||
val (senderDisplayName, senderAvatarUrl) = currentTimelineItem.getSenderInfo()
|
val (senderDisambiguatedDisplayName, senderAvatarUrl) = currentTimelineItem.getSenderInfo()
|
||||||
|
|
||||||
val timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT)
|
val timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT)
|
||||||
val sentTime = timeFormatter.format(Date(currentTimelineItem.event.timestamp))
|
val sentTime = timeFormatter.format(Date(currentTimelineItem.event.timestamp))
|
||||||
|
|
||||||
val senderAvatarData = AvatarData(
|
val senderAvatarData = AvatarData(
|
||||||
id = currentSender.value,
|
id = currentSender.value,
|
||||||
name = senderDisplayName ?: currentSender.value,
|
name = senderDisambiguatedDisplayName ?: currentSender.value,
|
||||||
url = senderAvatarUrl,
|
url = senderAvatarUrl,
|
||||||
size = AvatarSize.TimelineSender
|
size = AvatarSize.TimelineSender
|
||||||
)
|
)
|
||||||
|
|
@ -72,7 +72,7 @@ class TimelineItemEventFactory @Inject constructor(
|
||||||
eventId = currentTimelineItem.eventId,
|
eventId = currentTimelineItem.eventId,
|
||||||
transactionId = currentTimelineItem.transactionId,
|
transactionId = currentTimelineItem.transactionId,
|
||||||
senderId = currentSender,
|
senderId = currentSender,
|
||||||
senderDisplayName = senderDisplayName,
|
senderDisambiguatedDisplayName = senderDisambiguatedDisplayName,
|
||||||
senderAvatar = senderAvatarData,
|
senderAvatar = senderAvatarData,
|
||||||
content = contentFactory.create(currentTimelineItem.event),
|
content = contentFactory.create(currentTimelineItem.event),
|
||||||
isMine = currentTimelineItem.event.isOwn,
|
isMine = currentTimelineItem.event.isOwn,
|
||||||
|
|
@ -100,23 +100,23 @@ class TimelineItemEventFactory @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MatrixTimelineItem.Event.getSenderInfo(): Pair<String?, String?> {
|
private fun MatrixTimelineItem.Event.getSenderInfo(): Pair<String?, String?> {
|
||||||
val senderDisplayName: String?
|
val senderDisambiguatedDisplayName: String?
|
||||||
val senderAvatarUrl: String?
|
val senderAvatarUrl: String?
|
||||||
|
|
||||||
when (val senderProfile = event.senderProfile) {
|
when (val senderProfile = event.senderProfile) {
|
||||||
ProfileTimelineDetails.Unavailable,
|
ProfileTimelineDetails.Unavailable,
|
||||||
ProfileTimelineDetails.Pending,
|
ProfileTimelineDetails.Pending,
|
||||||
is ProfileTimelineDetails.Error -> {
|
is ProfileTimelineDetails.Error -> {
|
||||||
senderDisplayName = null
|
senderDisambiguatedDisplayName = null
|
||||||
senderAvatarUrl = null
|
senderAvatarUrl = null
|
||||||
}
|
}
|
||||||
is ProfileTimelineDetails.Ready -> {
|
is ProfileTimelineDetails.Ready -> {
|
||||||
senderDisplayName = senderProfile.getDisambiguatedDisplayName(event.sender)
|
senderDisambiguatedDisplayName = senderProfile.getDisambiguatedDisplayName(event.sender)
|
||||||
senderAvatarUrl = senderProfile.avatarUrl
|
senderAvatarUrl = senderProfile.avatarUrl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return senderDisplayName to senderAvatarUrl
|
return senderDisambiguatedDisplayName to senderAvatarUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MatrixTimelineItem.Event.computeReactionsState(): TimelineItemReactions {
|
private fun MatrixTimelineItem.Event.computeReactionsState(): TimelineItemReactions {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
|
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
import io.element.android.libraries.matrix.ui.messages.toPlainText
|
import io.element.android.libraries.matrix.ui.messages.toPlainText
|
||||||
|
|
@ -29,8 +30,7 @@ import io.element.android.libraries.matrix.ui.messages.toPlainText
|
||||||
data class InReplyToDetails(
|
data class InReplyToDetails(
|
||||||
val eventId: EventId,
|
val eventId: EventId,
|
||||||
val senderId: UserId,
|
val senderId: UserId,
|
||||||
val senderDisplayName: String?,
|
val senderProfile: ProfileTimelineDetails,
|
||||||
val senderAvatarUrl: String?,
|
|
||||||
val eventContent: EventContent?,
|
val eventContent: EventContent?,
|
||||||
val textContent: String?,
|
val textContent: String?,
|
||||||
)
|
)
|
||||||
|
|
@ -41,8 +41,7 @@ fun InReplyTo.map(
|
||||||
is InReplyTo.Ready -> InReplyToDetails(
|
is InReplyTo.Ready -> InReplyToDetails(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
senderId = senderId,
|
senderId = senderId,
|
||||||
senderDisplayName = senderDisplayName,
|
senderProfile = senderProfile,
|
||||||
senderAvatarUrl = senderAvatarUrl,
|
|
||||||
eventContent = content,
|
eventContent = content,
|
||||||
textContent = when (content) {
|
textContent = when (content) {
|
||||||
is MessageContent -> {
|
is MessageContent -> {
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ sealed interface TimelineItem {
|
||||||
val eventId: EventId? = null,
|
val eventId: EventId? = null,
|
||||||
val transactionId: TransactionId? = null,
|
val transactionId: TransactionId? = null,
|
||||||
val senderId: UserId,
|
val senderId: UserId,
|
||||||
val senderDisplayName: String?,
|
val senderDisambiguatedDisplayName: String?,
|
||||||
val senderAvatar: AvatarData,
|
val senderAvatar: AvatarData,
|
||||||
val content: TimelineItemEventContent,
|
val content: TimelineItemEventContent,
|
||||||
val sentTime: String = "",
|
val sentTime: String = "",
|
||||||
|
|
@ -74,7 +74,7 @@ sealed interface TimelineItem {
|
||||||
) : TimelineItem {
|
) : TimelineItem {
|
||||||
val showSenderInformation = groupPosition.isNew() && !isMine
|
val showSenderInformation = groupPosition.isNew() && !isMine
|
||||||
|
|
||||||
val safeSenderName: String = senderDisplayName ?: senderId.value
|
val safeSenderName: String = senderDisambiguatedDisplayName ?: senderId.value
|
||||||
|
|
||||||
val failedToSend: Boolean = localSendState is LocalEventSendState.SendingFailed
|
val failedToSend: Boolean = localSendState is LocalEventSendState.SendingFailed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ internal fun aMessageEvent(
|
||||||
id = eventId?.value.orEmpty(),
|
id = eventId?.value.orEmpty(),
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
senderId = A_USER_ID,
|
senderId = A_USER_ID,
|
||||||
senderDisplayName = A_USER_NAME,
|
senderDisambiguatedDisplayName = A_USER_NAME,
|
||||||
senderAvatar = AvatarData(A_USER_ID.value, A_USER_NAME, size = AvatarSize.TimelineSender),
|
senderAvatar = AvatarData(A_USER_ID.value, A_USER_NAME, size = AvatarSize.TimelineSender),
|
||||||
content = content,
|
content = content,
|
||||||
sentTime = "",
|
sentTime = "",
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
val sut = createTimelineItemContentMessageFactory()
|
val sut = createTimelineItemContentMessageFactory()
|
||||||
val result = sut.create(
|
val result = sut.create(
|
||||||
content = createMessageContent(type = OtherMessageType(msgType = "a_type", body = "body")),
|
content = createMessageContent(type = OtherMessageType(msgType = "a_type", body = "body")),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemTextContent(
|
val expected = TimelineItemTextContent(
|
||||||
|
|
@ -100,7 +100,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
val sut = createTimelineItemContentMessageFactory()
|
val sut = createTimelineItemContentMessageFactory()
|
||||||
val result = sut.create(
|
val result = sut.create(
|
||||||
content = createMessageContent(type = LocationMessageType("body", "geo:1,2", "description")),
|
content = createMessageContent(type = LocationMessageType("body", "geo:1,2", "description")),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemLocationContent(
|
val expected = TimelineItemLocationContent(
|
||||||
|
|
@ -116,7 +116,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
val sut = createTimelineItemContentMessageFactory()
|
val sut = createTimelineItemContentMessageFactory()
|
||||||
val result = sut.create(
|
val result = sut.create(
|
||||||
content = createMessageContent(type = LocationMessageType("body", "", null)),
|
content = createMessageContent(type = LocationMessageType("body", "", null)),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemTextContent(
|
val expected = TimelineItemTextContent(
|
||||||
|
|
@ -134,7 +134,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
val sut = createTimelineItemContentMessageFactory()
|
val sut = createTimelineItemContentMessageFactory()
|
||||||
val result = sut.create(
|
val result = sut.create(
|
||||||
content = createMessageContent(type = TextMessageType("body", null)),
|
content = createMessageContent(type = TextMessageType("body", null)),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemTextContent(
|
val expected = TimelineItemTextContent(
|
||||||
|
|
@ -152,7 +152,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
val sut = createTimelineItemContentMessageFactory()
|
val sut = createTimelineItemContentMessageFactory()
|
||||||
val result = sut.create(
|
val result = sut.create(
|
||||||
content = createMessageContent(type = TextMessageType("https://www.example.org", null)),
|
content = createMessageContent(type = TextMessageType("https://www.example.org", null)),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
) as TimelineItemTextContent
|
) as TimelineItemTextContent
|
||||||
val expected = TimelineItemTextContent(
|
val expected = TimelineItemTextContent(
|
||||||
|
|
@ -200,7 +200,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
formatted = FormattedBody(MessageFormat.HTML, expected.toString())
|
formatted = FormattedBody(MessageFormat.HTML, expected.toString())
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
assertThat((result as TimelineItemTextContent).formattedBody).isEqualTo(expected)
|
assertThat((result as TimelineItemTextContent).formattedBody).isEqualTo(expected)
|
||||||
|
|
@ -218,7 +218,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
formatted = FormattedBody(MessageFormat.UNKNOWN, "formatted")
|
formatted = FormattedBody(MessageFormat.UNKNOWN, "formatted")
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
assertThat((result as TimelineItemTextContent).formattedBody).isNull()
|
assertThat((result as TimelineItemTextContent).formattedBody).isNull()
|
||||||
|
|
@ -229,7 +229,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
val sut = createTimelineItemContentMessageFactory()
|
val sut = createTimelineItemContentMessageFactory()
|
||||||
val result = sut.create(
|
val result = sut.create(
|
||||||
content = createMessageContent(type = VideoMessageType("body", null, null, MediaSource("url"), null)),
|
content = createMessageContent(type = VideoMessageType("body", null, null, MediaSource("url"), null)),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemVideoContent(
|
val expected = TimelineItemVideoContent(
|
||||||
|
|
@ -277,7 +277,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemVideoContent(
|
val expected = TimelineItemVideoContent(
|
||||||
|
|
@ -303,7 +303,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
val sut = createTimelineItemContentMessageFactory()
|
val sut = createTimelineItemContentMessageFactory()
|
||||||
val result = sut.create(
|
val result = sut.create(
|
||||||
content = createMessageContent(type = AudioMessageType("body", MediaSource("url"), null)),
|
content = createMessageContent(type = AudioMessageType("body", MediaSource("url"), null)),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemAudioContent(
|
val expected = TimelineItemAudioContent(
|
||||||
|
|
@ -332,7 +332,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemAudioContent(
|
val expected = TimelineItemAudioContent(
|
||||||
|
|
@ -351,7 +351,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
val sut = createTimelineItemContentMessageFactory()
|
val sut = createTimelineItemContentMessageFactory()
|
||||||
val result = sut.create(
|
val result = sut.create(
|
||||||
content = createMessageContent(type = VoiceMessageType("body", MediaSource("url"), null, null)),
|
content = createMessageContent(type = VoiceMessageType("body", MediaSource("url"), null, null)),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemVoiceContent(
|
val expected = TimelineItemVoiceContent(
|
||||||
|
|
@ -384,7 +384,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemVoiceContent(
|
val expected = TimelineItemVoiceContent(
|
||||||
|
|
@ -409,7 +409,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
)
|
)
|
||||||
val result = sut.create(
|
val result = sut.create(
|
||||||
content = createMessageContent(type = VoiceMessageType("body", MediaSource("url"), null, null)),
|
content = createMessageContent(type = VoiceMessageType("body", MediaSource("url"), null, null)),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemAudioContent(
|
val expected = TimelineItemAudioContent(
|
||||||
|
|
@ -428,7 +428,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
val sut = createTimelineItemContentMessageFactory()
|
val sut = createTimelineItemContentMessageFactory()
|
||||||
val result = sut.create(
|
val result = sut.create(
|
||||||
content = createMessageContent(type = ImageMessageType("body", null, null, MediaSource("url"), null)),
|
content = createMessageContent(type = ImageMessageType("body", null, null, MediaSource("url"), null)),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemImageContent(
|
val expected = TimelineItemImageContent(
|
||||||
|
|
@ -499,7 +499,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemImageContent(
|
val expected = TimelineItemImageContent(
|
||||||
|
|
@ -524,7 +524,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
val sut = createTimelineItemContentMessageFactory()
|
val sut = createTimelineItemContentMessageFactory()
|
||||||
val result = sut.create(
|
val result = sut.create(
|
||||||
content = createMessageContent(type = FileMessageType("body", MediaSource("url"), null)),
|
content = createMessageContent(type = FileMessageType("body", MediaSource("url"), null)),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemFileContent(
|
val expected = TimelineItemFileContent(
|
||||||
|
|
@ -559,7 +559,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemFileContent(
|
val expected = TimelineItemFileContent(
|
||||||
|
|
@ -578,7 +578,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
val sut = createTimelineItemContentMessageFactory()
|
val sut = createTimelineItemContentMessageFactory()
|
||||||
val result = sut.create(
|
val result = sut.create(
|
||||||
content = createMessageContent(type = NoticeMessageType("body", null)),
|
content = createMessageContent(type = NoticeMessageType("body", null)),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemNoticeContent(
|
val expected = TimelineItemNoticeContent(
|
||||||
|
|
@ -601,7 +601,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
formatted = FormattedBody(MessageFormat.HTML, "formatted")
|
formatted = FormattedBody(MessageFormat.HTML, "formatted")
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
assertThat((result as TimelineItemNoticeContent).formattedBody).isEqualTo("formatted")
|
assertThat((result as TimelineItemNoticeContent).formattedBody).isEqualTo("formatted")
|
||||||
|
|
@ -612,7 +612,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
val sut = createTimelineItemContentMessageFactory()
|
val sut = createTimelineItemContentMessageFactory()
|
||||||
val result = sut.create(
|
val result = sut.create(
|
||||||
content = createMessageContent(type = EmoteMessageType("body", null)),
|
content = createMessageContent(type = EmoteMessageType("body", null)),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
val expected = TimelineItemEmoteContent(
|
val expected = TimelineItemEmoteContent(
|
||||||
|
|
@ -635,7 +635,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
formatted = FormattedBody(MessageFormat.HTML, "formatted")
|
formatted = FormattedBody(MessageFormat.HTML, "formatted")
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
senderDisplayName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
)
|
)
|
||||||
assertThat((result as TimelineItemEmoteContent).formattedBody).isEqualTo(SpannableString("* Bob formatted"))
|
assertThat((result as TimelineItemEmoteContent).formattedBody).isEqualTo(SpannableString("* Bob formatted"))
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class TimelineItemGrouperTest {
|
||||||
id = "0",
|
id = "0",
|
||||||
senderId = A_USER_ID,
|
senderId = A_USER_ID,
|
||||||
senderAvatar = anAvatarData(),
|
senderAvatar = anAvatarData(),
|
||||||
senderDisplayName = "",
|
senderDisambiguatedDisplayName = "",
|
||||||
content = TimelineItemStateEventContent(body = "a state event"),
|
content = TimelineItemStateEventContent(body = "a state event"),
|
||||||
reactionsState = aTimelineItemReactions(count = 0),
|
reactionsState = aTimelineItemReactions(count = 0),
|
||||||
readReceiptState = TimelineItemReadReceipts(emptyList<ReadReceiptData>().toImmutableList()),
|
readReceiptState = TimelineItemReadReceipts(emptyList<ReadReceiptData>().toImmutableList()),
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageTy
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
||||||
|
import io.element.android.libraries.matrix.test.timeline.aProfileTimelineDetails
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class InReplyToDetailTest {
|
class InReplyToDetailTest {
|
||||||
|
|
@ -54,8 +55,7 @@ class InReplyToDetailTest {
|
||||||
val inReplyTo = InReplyTo.Ready(
|
val inReplyTo = InReplyTo.Ready(
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
senderId = A_USER_ID,
|
senderId = A_USER_ID,
|
||||||
senderDisplayName = "senderDisplayName",
|
senderProfile = aProfileTimelineDetails(),
|
||||||
senderAvatarUrl = "senderAvatarUrl",
|
|
||||||
content = RoomMembershipContent(
|
content = RoomMembershipContent(
|
||||||
userId = A_USER_ID,
|
userId = A_USER_ID,
|
||||||
change = MembershipChange.INVITED,
|
change = MembershipChange.INVITED,
|
||||||
|
|
@ -73,8 +73,7 @@ class InReplyToDetailTest {
|
||||||
val inReplyTo = InReplyTo.Ready(
|
val inReplyTo = InReplyTo.Ready(
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
senderId = A_USER_ID,
|
senderId = A_USER_ID,
|
||||||
senderDisplayName = "senderDisplayName",
|
senderProfile = aProfileTimelineDetails(),
|
||||||
senderAvatarUrl = "senderAvatarUrl",
|
|
||||||
content = MessageContent(
|
content = MessageContent(
|
||||||
body = "**Hello!**",
|
body = "**Hello!**",
|
||||||
inReplyTo = null,
|
inReplyTo = null,
|
||||||
|
|
@ -101,8 +100,7 @@ class InReplyToDetailTest {
|
||||||
val inReplyTo = InReplyTo.Ready(
|
val inReplyTo = InReplyTo.Ready(
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
senderId = A_USER_ID,
|
senderId = A_USER_ID,
|
||||||
senderDisplayName = "senderDisplayName",
|
senderProfile = aProfileTimelineDetails(),
|
||||||
senderAvatarUrl = "senderAvatarUrl",
|
|
||||||
content = MessageContent(
|
content = MessageContent(
|
||||||
body = "**Hello!**",
|
body = "**Hello!**",
|
||||||
inReplyTo = null,
|
inReplyTo = null,
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageT
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
|
import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
||||||
|
|
@ -55,6 +56,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
import io.element.android.libraries.matrix.test.media.aMediaSource
|
import io.element.android.libraries.matrix.test.media.aMediaSource
|
||||||
import io.element.android.libraries.matrix.test.timeline.aMessageContent
|
import io.element.android.libraries.matrix.test.timeline.aMessageContent
|
||||||
import io.element.android.libraries.matrix.test.timeline.aPollContent
|
import io.element.android.libraries.matrix.test.timeline.aPollContent
|
||||||
|
import io.element.android.libraries.matrix.test.timeline.aProfileTimelineDetails
|
||||||
import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH
|
import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH
|
||||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
|
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
|
||||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
|
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
|
||||||
|
|
@ -430,15 +432,13 @@ class InReplyToMetadataKtTest {
|
||||||
fun anInReplyToDetails(
|
fun anInReplyToDetails(
|
||||||
eventId: EventId = AN_EVENT_ID,
|
eventId: EventId = AN_EVENT_ID,
|
||||||
senderId: UserId = A_USER_ID,
|
senderId: UserId = A_USER_ID,
|
||||||
senderDisplayName: String? = "senderDisplayName",
|
senderProfile: ProfileTimelineDetails = aProfileTimelineDetails(),
|
||||||
senderAvatarUrl: String? = "senderAvatarUrl",
|
|
||||||
eventContent: EventContent? = aMessageContent(),
|
eventContent: EventContent? = aMessageContent(),
|
||||||
textContent: String? = "textContent",
|
textContent: String? = "textContent",
|
||||||
) = InReplyToDetails(
|
) = InReplyToDetails(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
senderId = senderId,
|
senderId = senderId,
|
||||||
senderDisplayName = senderDisplayName,
|
senderProfile = senderProfile,
|
||||||
senderAvatarUrl = senderAvatarUrl,
|
|
||||||
eventContent = eventContent,
|
eventContent = eventContent,
|
||||||
textContent = textContent,
|
textContent = textContent,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessage
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
||||||
|
|
@ -52,6 +51,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecry
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
|
||||||
import io.element.android.libraries.matrix.ui.messages.toPlainText
|
import io.element.android.libraries.matrix.ui.messages.toPlainText
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||||
|
|
@ -72,15 +72,13 @@ class DefaultRoomLastMessageFormatter @Inject constructor(
|
||||||
|
|
||||||
override fun format(event: EventTimelineItem, isDmRoom: Boolean): CharSequence? {
|
override fun format(event: EventTimelineItem, isDmRoom: Boolean): CharSequence? {
|
||||||
val isOutgoing = event.isOwn
|
val isOutgoing = event.isOwn
|
||||||
// Note: we do not use disambiguated display name here, see
|
val senderDisambiguatedDisplayName = event.senderProfile.getDisambiguatedDisplayName(event.sender)
|
||||||
// https://github.com/element-hq/element-x-ios/issues/1845#issuecomment-1888707428
|
|
||||||
val senderDisplayName = (event.senderProfile as? ProfileTimelineDetails.Ready)?.displayName ?: event.sender.value
|
|
||||||
return when (val content = event.content) {
|
return when (val content = event.content) {
|
||||||
is MessageContent -> processMessageContents(content, senderDisplayName, isDmRoom)
|
is MessageContent -> processMessageContents(content, senderDisambiguatedDisplayName, isDmRoom)
|
||||||
RedactedContent -> {
|
RedactedContent -> {
|
||||||
val message = sp.getString(CommonStrings.common_message_removed)
|
val message = sp.getString(CommonStrings.common_message_removed)
|
||||||
if (!isDmRoom) {
|
if (!isDmRoom) {
|
||||||
prefix(message, senderDisplayName)
|
prefix(message, senderDisambiguatedDisplayName)
|
||||||
} else {
|
} else {
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
|
|
@ -91,36 +89,40 @@ class DefaultRoomLastMessageFormatter @Inject constructor(
|
||||||
is UnableToDecryptContent -> {
|
is UnableToDecryptContent -> {
|
||||||
val message = sp.getString(CommonStrings.common_waiting_for_decryption_key)
|
val message = sp.getString(CommonStrings.common_waiting_for_decryption_key)
|
||||||
if (!isDmRoom) {
|
if (!isDmRoom) {
|
||||||
prefix(message, senderDisplayName)
|
prefix(message, senderDisambiguatedDisplayName)
|
||||||
} else {
|
} else {
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is RoomMembershipContent -> {
|
is RoomMembershipContent -> {
|
||||||
roomMembershipContentFormatter.format(content, senderDisplayName, isOutgoing)
|
roomMembershipContentFormatter.format(content, senderDisambiguatedDisplayName, isOutgoing)
|
||||||
}
|
}
|
||||||
is ProfileChangeContent -> {
|
is ProfileChangeContent -> {
|
||||||
profileChangeContentFormatter.format(content, event.sender, senderDisplayName, isOutgoing)
|
profileChangeContentFormatter.format(content, event.sender, senderDisambiguatedDisplayName, isOutgoing)
|
||||||
}
|
}
|
||||||
is StateContent -> {
|
is StateContent -> {
|
||||||
stateContentFormatter.format(content, senderDisplayName, isOutgoing, RenderingMode.RoomList)
|
stateContentFormatter.format(content, senderDisambiguatedDisplayName, isOutgoing, RenderingMode.RoomList)
|
||||||
}
|
}
|
||||||
is PollContent -> {
|
is PollContent -> {
|
||||||
val message = sp.getString(CommonStrings.common_poll_summary, content.question)
|
val message = sp.getString(CommonStrings.common_poll_summary, content.question)
|
||||||
prefixIfNeeded(message, senderDisplayName, isDmRoom)
|
prefixIfNeeded(message, senderDisambiguatedDisplayName, isDmRoom)
|
||||||
}
|
}
|
||||||
is FailedToParseMessageLikeContent, is FailedToParseStateContent, is UnknownContent -> {
|
is FailedToParseMessageLikeContent, is FailedToParseStateContent, is UnknownContent -> {
|
||||||
prefixIfNeeded(sp.getString(CommonStrings.common_unsupported_event), senderDisplayName, isDmRoom)
|
prefixIfNeeded(sp.getString(CommonStrings.common_unsupported_event), senderDisambiguatedDisplayName, isDmRoom)
|
||||||
}
|
}
|
||||||
is LegacyCallInviteContent -> sp.getString(CommonStrings.common_call_invite)
|
is LegacyCallInviteContent -> sp.getString(CommonStrings.common_call_invite)
|
||||||
}?.take(MAX_SAFE_LENGTH)
|
}?.take(MAX_SAFE_LENGTH)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processMessageContents(messageContent: MessageContent, senderDisplayName: String, isDmRoom: Boolean): CharSequence? {
|
private fun processMessageContents(
|
||||||
|
messageContent: MessageContent,
|
||||||
|
senderDisambiguatedDisplayName: String,
|
||||||
|
isDmRoom: Boolean,
|
||||||
|
): CharSequence {
|
||||||
val internalMessage = when (val messageType: MessageType = messageContent.type) {
|
val internalMessage = when (val messageType: MessageType = messageContent.type) {
|
||||||
// Doesn't need a prefix
|
// Doesn't need a prefix
|
||||||
is EmoteMessageType -> {
|
is EmoteMessageType -> {
|
||||||
return "* $senderDisplayName ${messageType.body}"
|
return "* $senderDisambiguatedDisplayName ${messageType.body}"
|
||||||
}
|
}
|
||||||
is TextMessageType -> {
|
is TextMessageType -> {
|
||||||
messageType.toPlainText(permalinkParser)
|
messageType.toPlainText(permalinkParser)
|
||||||
|
|
@ -153,19 +155,23 @@ class DefaultRoomLastMessageFormatter @Inject constructor(
|
||||||
messageType.body
|
messageType.body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return prefixIfNeeded(internalMessage, senderDisplayName, isDmRoom)
|
return prefixIfNeeded(internalMessage, senderDisambiguatedDisplayName, isDmRoom)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prefixIfNeeded(message: String, senderDisplayName: String, isDmRoom: Boolean): CharSequence = if (isDmRoom) {
|
private fun prefixIfNeeded(
|
||||||
|
message: String,
|
||||||
|
senderDisambiguatedDisplayName: String,
|
||||||
|
isDmRoom: Boolean,
|
||||||
|
): CharSequence = if (isDmRoom) {
|
||||||
message
|
message
|
||||||
} else {
|
} else {
|
||||||
prefix(message, senderDisplayName)
|
prefix(message, senderDisambiguatedDisplayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prefix(message: String, senderDisplayName: String): AnnotatedString {
|
private fun prefix(message: String, senderDisambiguatedDisplayName: String): AnnotatedString {
|
||||||
return buildAnnotatedString {
|
return buildAnnotatedString {
|
||||||
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
||||||
append(senderDisplayName)
|
append(senderDisambiguatedDisplayName)
|
||||||
}
|
}
|
||||||
append(": ")
|
append(": ")
|
||||||
append(message)
|
append(message)
|
||||||
|
|
|
||||||
|
|
@ -49,16 +49,16 @@ class DefaultTimelineEventFormatter @Inject constructor(
|
||||||
) : TimelineEventFormatter {
|
) : TimelineEventFormatter {
|
||||||
override fun format(event: EventTimelineItem): CharSequence? {
|
override fun format(event: EventTimelineItem): CharSequence? {
|
||||||
val isOutgoing = event.isOwn
|
val isOutgoing = event.isOwn
|
||||||
val senderDisplayName = event.senderProfile.getDisambiguatedDisplayName(event.sender)
|
val senderDisambiguatedDisplayName = event.senderProfile.getDisambiguatedDisplayName(event.sender)
|
||||||
return when (val content = event.content) {
|
return when (val content = event.content) {
|
||||||
is RoomMembershipContent -> {
|
is RoomMembershipContent -> {
|
||||||
roomMembershipContentFormatter.format(content, senderDisplayName, isOutgoing)
|
roomMembershipContentFormatter.format(content, senderDisambiguatedDisplayName, isOutgoing)
|
||||||
}
|
}
|
||||||
is ProfileChangeContent -> {
|
is ProfileChangeContent -> {
|
||||||
profileChangeContentFormatter.format(content, event.sender, senderDisplayName, isOutgoing)
|
profileChangeContentFormatter.format(content, event.sender, senderDisambiguatedDisplayName, isOutgoing)
|
||||||
}
|
}
|
||||||
is StateContent -> {
|
is StateContent -> {
|
||||||
stateContentFormatter.format(content, senderDisplayName, isOutgoing, RenderingMode.Timeline)
|
stateContentFormatter.format(content, senderDisambiguatedDisplayName, isOutgoing, RenderingMode.Timeline)
|
||||||
}
|
}
|
||||||
is LegacyCallInviteContent -> {
|
is LegacyCallInviteContent -> {
|
||||||
sp.getString(CommonStrings.common_call_invite)
|
sp.getString(CommonStrings.common_call_invite)
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,19 @@ class ProfileChangeContentFormatter @Inject constructor(
|
||||||
fun format(
|
fun format(
|
||||||
profileChangeContent: ProfileChangeContent,
|
profileChangeContent: ProfileChangeContent,
|
||||||
senderId: UserId,
|
senderId: UserId,
|
||||||
senderDisplayName: String,
|
senderDisambiguatedDisplayName: String,
|
||||||
senderIsYou: Boolean,
|
senderIsYou: Boolean,
|
||||||
): String? = profileChangeContent.run {
|
): String? = profileChangeContent.run {
|
||||||
val displayNameChanged = displayName != prevDisplayName
|
val displayNameChanged = displayName != prevDisplayName
|
||||||
val avatarChanged = avatarUrl != prevAvatarUrl
|
val avatarChanged = avatarUrl != prevAvatarUrl
|
||||||
return when {
|
return when {
|
||||||
avatarChanged && displayNameChanged -> {
|
avatarChanged && displayNameChanged -> {
|
||||||
val message = format(profileChangeContent.copy(avatarUrl = null, prevAvatarUrl = null), senderId, senderDisplayName, senderIsYou)
|
val message = format(
|
||||||
|
profileChangeContent = profileChangeContent.copy(avatarUrl = null, prevAvatarUrl = null),
|
||||||
|
senderId = senderId,
|
||||||
|
senderDisambiguatedDisplayName = senderDisambiguatedDisplayName,
|
||||||
|
senderIsYou = senderIsYou,
|
||||||
|
)
|
||||||
val avatarChangedToo = sp.getString(R.string.state_event_avatar_changed_too)
|
val avatarChangedToo = sp.getString(R.string.state_event_avatar_changed_too)
|
||||||
"$message\n$avatarChangedToo"
|
"$message\n$avatarChangedToo"
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +68,7 @@ class ProfileChangeContentFormatter @Inject constructor(
|
||||||
if (senderIsYou) {
|
if (senderIsYou) {
|
||||||
sp.getString(R.string.state_event_avatar_url_changed_by_you)
|
sp.getString(R.string.state_event_avatar_url_changed_by_you)
|
||||||
} else {
|
} else {
|
||||||
sp.getString(R.string.state_event_avatar_url_changed, senderDisplayName)
|
sp.getString(R.string.state_event_avatar_url_changed, senderDisambiguatedDisplayName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class RoomMembershipContentFormatter @Inject constructor(
|
||||||
) {
|
) {
|
||||||
fun format(
|
fun format(
|
||||||
membershipContent: RoomMembershipContent,
|
membershipContent: RoomMembershipContent,
|
||||||
senderDisplayName: String,
|
senderDisambiguatedDisplayName: String,
|
||||||
senderIsYou: Boolean,
|
senderIsYou: Boolean,
|
||||||
): CharSequence? {
|
): CharSequence? {
|
||||||
val userId = membershipContent.userId
|
val userId = membershipContent.userId
|
||||||
|
|
@ -48,24 +48,24 @@ class RoomMembershipContentFormatter @Inject constructor(
|
||||||
MembershipChange.BANNED, MembershipChange.KICKED_AND_BANNED -> if (senderIsYou) {
|
MembershipChange.BANNED, MembershipChange.KICKED_AND_BANNED -> if (senderIsYou) {
|
||||||
sp.getString(R.string.state_event_room_ban_by_you, userId.value)
|
sp.getString(R.string.state_event_room_ban_by_you, userId.value)
|
||||||
} else {
|
} else {
|
||||||
sp.getString(R.string.state_event_room_ban, senderDisplayName, userId.value)
|
sp.getString(R.string.state_event_room_ban, senderDisambiguatedDisplayName, userId.value)
|
||||||
}
|
}
|
||||||
MembershipChange.UNBANNED -> if (senderIsYou) {
|
MembershipChange.UNBANNED -> if (senderIsYou) {
|
||||||
sp.getString(R.string.state_event_room_unban_by_you, userId.value)
|
sp.getString(R.string.state_event_room_unban_by_you, userId.value)
|
||||||
} else {
|
} else {
|
||||||
sp.getString(R.string.state_event_room_unban, senderDisplayName, userId.value)
|
sp.getString(R.string.state_event_room_unban, senderDisambiguatedDisplayName, userId.value)
|
||||||
}
|
}
|
||||||
MembershipChange.KICKED -> if (senderIsYou) {
|
MembershipChange.KICKED -> if (senderIsYou) {
|
||||||
sp.getString(R.string.state_event_room_remove_by_you, userId.value)
|
sp.getString(R.string.state_event_room_remove_by_you, userId.value)
|
||||||
} else {
|
} else {
|
||||||
sp.getString(R.string.state_event_room_remove, senderDisplayName, userId.value)
|
sp.getString(R.string.state_event_room_remove, senderDisambiguatedDisplayName, userId.value)
|
||||||
}
|
}
|
||||||
MembershipChange.INVITED -> if (senderIsYou) {
|
MembershipChange.INVITED -> if (senderIsYou) {
|
||||||
sp.getString(R.string.state_event_room_invite_by_you, userId.value)
|
sp.getString(R.string.state_event_room_invite_by_you, userId.value)
|
||||||
} else if (memberIsYou) {
|
} else if (memberIsYou) {
|
||||||
sp.getString(R.string.state_event_room_invite_you, senderDisplayName)
|
sp.getString(R.string.state_event_room_invite_you, senderDisambiguatedDisplayName)
|
||||||
} else {
|
} else {
|
||||||
sp.getString(R.string.state_event_room_invite, senderDisplayName, userId.value)
|
sp.getString(R.string.state_event_room_invite, senderDisambiguatedDisplayName, userId.value)
|
||||||
}
|
}
|
||||||
MembershipChange.INVITATION_ACCEPTED -> if (memberIsYou) {
|
MembershipChange.INVITATION_ACCEPTED -> if (memberIsYou) {
|
||||||
sp.getString(R.string.state_event_room_invite_accepted_by_you)
|
sp.getString(R.string.state_event_room_invite_accepted_by_you)
|
||||||
|
|
@ -80,7 +80,7 @@ class RoomMembershipContentFormatter @Inject constructor(
|
||||||
MembershipChange.INVITATION_REVOKED -> if (senderIsYou) {
|
MembershipChange.INVITATION_REVOKED -> if (senderIsYou) {
|
||||||
sp.getString(R.string.state_event_room_third_party_revoked_invite_by_you, userId.value)
|
sp.getString(R.string.state_event_room_third_party_revoked_invite_by_you, userId.value)
|
||||||
} else {
|
} else {
|
||||||
sp.getString(R.string.state_event_room_third_party_revoked_invite, senderDisplayName, userId.value)
|
sp.getString(R.string.state_event_room_third_party_revoked_invite, senderDisambiguatedDisplayName, userId.value)
|
||||||
}
|
}
|
||||||
MembershipChange.KNOCKED -> if (memberIsYou) {
|
MembershipChange.KNOCKED -> if (memberIsYou) {
|
||||||
sp.getString(R.string.state_event_room_knock_by_you)
|
sp.getString(R.string.state_event_room_knock_by_you)
|
||||||
|
|
@ -90,7 +90,7 @@ class RoomMembershipContentFormatter @Inject constructor(
|
||||||
MembershipChange.KNOCK_ACCEPTED -> if (senderIsYou) {
|
MembershipChange.KNOCK_ACCEPTED -> if (senderIsYou) {
|
||||||
sp.getString(R.string.state_event_room_knock_accepted_by_you, userId.value)
|
sp.getString(R.string.state_event_room_knock_accepted_by_you, userId.value)
|
||||||
} else {
|
} else {
|
||||||
sp.getString(R.string.state_event_room_knock_accepted, senderDisplayName, userId.value)
|
sp.getString(R.string.state_event_room_knock_accepted, senderDisambiguatedDisplayName, userId.value)
|
||||||
}
|
}
|
||||||
MembershipChange.KNOCK_RETRACTED -> if (memberIsYou) {
|
MembershipChange.KNOCK_RETRACTED -> if (memberIsYou) {
|
||||||
sp.getString(R.string.state_event_room_knock_retracted_by_you)
|
sp.getString(R.string.state_event_room_knock_retracted_by_you)
|
||||||
|
|
@ -100,14 +100,14 @@ class RoomMembershipContentFormatter @Inject constructor(
|
||||||
MembershipChange.KNOCK_DENIED -> if (senderIsYou) {
|
MembershipChange.KNOCK_DENIED -> if (senderIsYou) {
|
||||||
sp.getString(R.string.state_event_room_knock_denied_by_you, userId.value)
|
sp.getString(R.string.state_event_room_knock_denied_by_you, userId.value)
|
||||||
} else if (memberIsYou) {
|
} else if (memberIsYou) {
|
||||||
sp.getString(R.string.state_event_room_knock_denied_you, senderDisplayName)
|
sp.getString(R.string.state_event_room_knock_denied_you, senderDisambiguatedDisplayName)
|
||||||
} else {
|
} else {
|
||||||
sp.getString(R.string.state_event_room_knock_denied, senderDisplayName, userId.value)
|
sp.getString(R.string.state_event_room_knock_denied, senderDisambiguatedDisplayName, userId.value)
|
||||||
}
|
}
|
||||||
MembershipChange.NONE -> if (senderIsYou) {
|
MembershipChange.NONE -> if (senderIsYou) {
|
||||||
sp.getString(R.string.state_event_room_none_by_you)
|
sp.getString(R.string.state_event_room_none_by_you)
|
||||||
} else {
|
} else {
|
||||||
sp.getString(R.string.state_event_room_none, senderDisplayName)
|
sp.getString(R.string.state_event_room_none, senderDisambiguatedDisplayName)
|
||||||
}
|
}
|
||||||
MembershipChange.ERROR -> {
|
MembershipChange.ERROR -> {
|
||||||
Timber.v("Filtering timeline item for room membership: $membershipContent")
|
Timber.v("Filtering timeline item for room membership: $membershipContent")
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class StateContentFormatter @Inject constructor(
|
||||||
) {
|
) {
|
||||||
fun format(
|
fun format(
|
||||||
stateContent: StateContent,
|
stateContent: StateContent,
|
||||||
senderDisplayName: String,
|
senderDisambiguatedDisplayName: String,
|
||||||
senderIsYou: Boolean,
|
senderIsYou: Boolean,
|
||||||
renderingMode: RenderingMode,
|
renderingMode: RenderingMode,
|
||||||
): CharSequence? {
|
): CharSequence? {
|
||||||
|
|
@ -39,15 +39,15 @@ class StateContentFormatter @Inject constructor(
|
||||||
when {
|
when {
|
||||||
senderIsYou && hasAvatarUrl -> sp.getString(R.string.state_event_room_avatar_changed_by_you)
|
senderIsYou && hasAvatarUrl -> sp.getString(R.string.state_event_room_avatar_changed_by_you)
|
||||||
senderIsYou && !hasAvatarUrl -> sp.getString(R.string.state_event_room_avatar_removed_by_you)
|
senderIsYou && !hasAvatarUrl -> sp.getString(R.string.state_event_room_avatar_removed_by_you)
|
||||||
!senderIsYou && hasAvatarUrl -> sp.getString(R.string.state_event_room_avatar_changed, senderDisplayName)
|
!senderIsYou && hasAvatarUrl -> sp.getString(R.string.state_event_room_avatar_changed, senderDisambiguatedDisplayName)
|
||||||
else -> sp.getString(R.string.state_event_room_avatar_removed, senderDisplayName)
|
else -> sp.getString(R.string.state_event_room_avatar_removed, senderDisambiguatedDisplayName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is OtherState.RoomCreate -> {
|
is OtherState.RoomCreate -> {
|
||||||
if (senderIsYou) {
|
if (senderIsYou) {
|
||||||
sp.getString(R.string.state_event_room_created_by_you)
|
sp.getString(R.string.state_event_room_created_by_you)
|
||||||
} else {
|
} else {
|
||||||
sp.getString(R.string.state_event_room_created, senderDisplayName)
|
sp.getString(R.string.state_event_room_created, senderDisambiguatedDisplayName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is OtherState.RoomEncryption -> sp.getString(CommonStrings.common_encryption_enabled)
|
is OtherState.RoomEncryption -> sp.getString(CommonStrings.common_encryption_enabled)
|
||||||
|
|
@ -56,8 +56,8 @@ class StateContentFormatter @Inject constructor(
|
||||||
when {
|
when {
|
||||||
senderIsYou && hasRoomName -> sp.getString(R.string.state_event_room_name_changed_by_you, content.name)
|
senderIsYou && hasRoomName -> sp.getString(R.string.state_event_room_name_changed_by_you, content.name)
|
||||||
senderIsYou && !hasRoomName -> sp.getString(R.string.state_event_room_name_removed_by_you)
|
senderIsYou && !hasRoomName -> sp.getString(R.string.state_event_room_name_removed_by_you)
|
||||||
!senderIsYou && hasRoomName -> sp.getString(R.string.state_event_room_name_changed, senderDisplayName, content.name)
|
!senderIsYou && hasRoomName -> sp.getString(R.string.state_event_room_name_changed, senderDisambiguatedDisplayName, content.name)
|
||||||
else -> sp.getString(R.string.state_event_room_name_removed, senderDisplayName)
|
else -> sp.getString(R.string.state_event_room_name_removed, senderDisambiguatedDisplayName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is OtherState.RoomThirdPartyInvite -> {
|
is OtherState.RoomThirdPartyInvite -> {
|
||||||
|
|
@ -68,7 +68,7 @@ class StateContentFormatter @Inject constructor(
|
||||||
if (senderIsYou) {
|
if (senderIsYou) {
|
||||||
sp.getString(R.string.state_event_room_third_party_invite_by_you, content.displayName)
|
sp.getString(R.string.state_event_room_third_party_invite_by_you, content.displayName)
|
||||||
} else {
|
} else {
|
||||||
sp.getString(R.string.state_event_room_third_party_invite, senderDisplayName, content.displayName)
|
sp.getString(R.string.state_event_room_third_party_invite, senderDisambiguatedDisplayName, content.displayName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is OtherState.RoomTopic -> {
|
is OtherState.RoomTopic -> {
|
||||||
|
|
@ -76,8 +76,8 @@ class StateContentFormatter @Inject constructor(
|
||||||
when {
|
when {
|
||||||
senderIsYou && hasRoomTopic -> sp.getString(R.string.state_event_room_topic_changed_by_you, content.topic)
|
senderIsYou && hasRoomTopic -> sp.getString(R.string.state_event_room_topic_changed_by_you, content.topic)
|
||||||
senderIsYou && !hasRoomTopic -> sp.getString(R.string.state_event_room_topic_removed_by_you)
|
senderIsYou && !hasRoomTopic -> sp.getString(R.string.state_event_room_topic_removed_by_you)
|
||||||
!senderIsYou && hasRoomTopic -> sp.getString(R.string.state_event_room_topic_changed, senderDisplayName, content.topic)
|
!senderIsYou && hasRoomTopic -> sp.getString(R.string.state_event_room_topic_changed, senderDisambiguatedDisplayName, content.topic)
|
||||||
else -> sp.getString(R.string.state_event_room_topic_removed, senderDisplayName)
|
else -> sp.getString(R.string.state_event_room_topic_removed, senderDisambiguatedDisplayName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is OtherState.Custom -> when (renderingMode) {
|
is OtherState.Custom -> when (renderingMode) {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ data class NotificationData(
|
||||||
val roomId: RoomId,
|
val roomId: RoomId,
|
||||||
// mxc url
|
// mxc url
|
||||||
val senderAvatarUrl: String?,
|
val senderAvatarUrl: String?,
|
||||||
// private, must use `getSenderName`
|
// private, must use `getDisambiguatedDisplayName`
|
||||||
private val senderDisplayName: String?,
|
private val senderDisplayName: String?,
|
||||||
private val senderIsNameAmbiguous: Boolean,
|
private val senderIsNameAmbiguous: Boolean,
|
||||||
val roomAvatarUrl: String?,
|
val roomAvatarUrl: String?,
|
||||||
|
|
@ -39,7 +39,7 @@ data class NotificationData(
|
||||||
val content: NotificationContent,
|
val content: NotificationContent,
|
||||||
val hasMention: Boolean,
|
val hasMention: Boolean,
|
||||||
) {
|
) {
|
||||||
fun getSenderName(userId: UserId): String = when {
|
fun getDisambiguatedDisplayName(userId: UserId): String = when {
|
||||||
senderDisplayName.isNullOrBlank() -> userId.value
|
senderDisplayName.isNullOrBlank() -> userId.value
|
||||||
senderIsNameAmbiguous -> "$senderDisplayName ($userId)"
|
senderIsNameAmbiguous -> "$senderDisplayName ($userId)"
|
||||||
else -> senderDisplayName
|
else -> senderDisplayName
|
||||||
|
|
@ -52,6 +52,7 @@ sealed interface NotificationContent {
|
||||||
data class CallInvite(
|
data class CallInvite(
|
||||||
val senderId: UserId,
|
val senderId: UserId,
|
||||||
) : MessageLike
|
) : MessageLike
|
||||||
|
|
||||||
data object CallHangup : MessageLike
|
data object CallHangup : MessageLike
|
||||||
data object CallCandidates : MessageLike
|
data object CallCandidates : MessageLike
|
||||||
data object KeyVerificationReady : MessageLike
|
data object KeyVerificationReady : MessageLike
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,7 @@ sealed interface InReplyTo {
|
||||||
val eventId: EventId,
|
val eventId: EventId,
|
||||||
val content: EventContent,
|
val content: EventContent,
|
||||||
val senderId: UserId,
|
val senderId: UserId,
|
||||||
val senderDisplayName: String?,
|
val senderProfile: ProfileTimelineDetails,
|
||||||
val senderAvatarUrl: String?,
|
|
||||||
) : InReplyTo
|
) : InReplyTo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageT
|
||||||
import io.element.android.libraries.matrix.impl.media.map
|
import io.element.android.libraries.matrix.impl.media.map
|
||||||
import org.matrix.rustcomponents.sdk.Message
|
import org.matrix.rustcomponents.sdk.Message
|
||||||
import org.matrix.rustcomponents.sdk.MessageType
|
import org.matrix.rustcomponents.sdk.MessageType
|
||||||
import org.matrix.rustcomponents.sdk.ProfileDetails
|
|
||||||
import org.matrix.rustcomponents.sdk.RepliedToEventDetails
|
import org.matrix.rustcomponents.sdk.RepliedToEventDetails
|
||||||
import org.matrix.rustcomponents.sdk.use
|
import org.matrix.rustcomponents.sdk.use
|
||||||
import org.matrix.rustcomponents.sdk.FormattedBody as RustFormattedBody
|
import org.matrix.rustcomponents.sdk.FormattedBody as RustFormattedBody
|
||||||
|
|
@ -51,13 +50,11 @@ class EventMessageMapper {
|
||||||
val inReplyToId = EventId(details.eventId)
|
val inReplyToId = EventId(details.eventId)
|
||||||
when (val event = details.event) {
|
when (val event = details.event) {
|
||||||
is RepliedToEventDetails.Ready -> {
|
is RepliedToEventDetails.Ready -> {
|
||||||
val senderProfile = event.senderProfile as? ProfileDetails.Ready
|
|
||||||
InReplyTo.Ready(
|
InReplyTo.Ready(
|
||||||
eventId = inReplyToId,
|
eventId = inReplyToId,
|
||||||
content = timelineEventContentMapper.map(event.content),
|
content = timelineEventContentMapper.map(event.content),
|
||||||
senderId = UserId(event.sender),
|
senderId = UserId(event.sender),
|
||||||
senderDisplayName = senderProfile?.displayName,
|
senderProfile = event.senderProfile.map(),
|
||||||
senderAvatarUrl = senderProfile?.avatarUrl,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is RepliedToEventDetails.Error -> InReplyTo.Error
|
is RepliedToEventDetails.Error -> InReplyTo.Error
|
||||||
|
|
|
||||||
|
|
@ -93,8 +93,8 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
): NotifiableEvent? {
|
): NotifiableEvent? {
|
||||||
return when (val content = this.content) {
|
return when (val content = this.content) {
|
||||||
is NotificationContent.MessageLike.RoomMessage -> {
|
is NotificationContent.MessageLike.RoomMessage -> {
|
||||||
val senderName = getSenderName(content.senderId)
|
val senderDisambiguatedDisplayName = getDisambiguatedDisplayName(content.senderId)
|
||||||
val messageBody = descriptionFromMessageContent(content, senderName)
|
val messageBody = descriptionFromMessageContent(content, senderDisambiguatedDisplayName)
|
||||||
val notificationBody = if (hasMention) {
|
val notificationBody = if (hasMention) {
|
||||||
stringProvider.getString(R.string.notification_mentioned_you_body, messageBody)
|
stringProvider.getString(R.string.notification_mentioned_you_body, messageBody)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -107,7 +107,7 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
noisy = isNoisy,
|
noisy = isNoisy,
|
||||||
timestamp = this.timestamp,
|
timestamp = this.timestamp,
|
||||||
senderName = senderName,
|
senderDisambiguatedDisplayName = senderDisambiguatedDisplayName,
|
||||||
body = notificationBody,
|
body = notificationBody,
|
||||||
imageUriString = fetchImageIfPresent(client)?.toString(),
|
imageUriString = fetchImageIfPresent(client)?.toString(),
|
||||||
roomName = roomDisplayName,
|
roomName = roomDisplayName,
|
||||||
|
|
@ -154,7 +154,7 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
noisy = isNoisy,
|
noisy = isNoisy,
|
||||||
timestamp = this.timestamp,
|
timestamp = this.timestamp,
|
||||||
senderName = null,
|
senderDisambiguatedDisplayName = getDisambiguatedDisplayName(content.senderId),
|
||||||
body = stringProvider.getString(CommonStrings.common_call_invite),
|
body = stringProvider.getString(CommonStrings.common_call_invite),
|
||||||
imageUriString = fetchImageIfPresent(client)?.toString(),
|
imageUriString = fetchImageIfPresent(client)?.toString(),
|
||||||
roomName = roomDisplayName,
|
roomName = roomDisplayName,
|
||||||
|
|
@ -180,7 +180,7 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
noisy = isNoisy,
|
noisy = isNoisy,
|
||||||
timestamp = this.timestamp,
|
timestamp = this.timestamp,
|
||||||
senderName = getSenderName(content.senderId),
|
senderDisambiguatedDisplayName = getDisambiguatedDisplayName(content.senderId),
|
||||||
body = stringProvider.getString(CommonStrings.common_poll_summary, content.question),
|
body = stringProvider.getString(CommonStrings.common_poll_summary, content.question),
|
||||||
imageUriString = null,
|
imageUriString = null,
|
||||||
roomName = roomDisplayName,
|
roomName = roomDisplayName,
|
||||||
|
|
@ -244,12 +244,12 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
|
|
||||||
private fun descriptionFromMessageContent(
|
private fun descriptionFromMessageContent(
|
||||||
content: NotificationContent.MessageLike.RoomMessage,
|
content: NotificationContent.MessageLike.RoomMessage,
|
||||||
senderDisplayName: String,
|
senderDisambiguatedDisplayName: String,
|
||||||
): String {
|
): String {
|
||||||
return when (val messageType = content.messageType) {
|
return when (val messageType = content.messageType) {
|
||||||
is AudioMessageType -> messageType.body
|
is AudioMessageType -> messageType.body
|
||||||
is VoiceMessageType -> stringProvider.getString(CommonStrings.common_voice_message)
|
is VoiceMessageType -> stringProvider.getString(CommonStrings.common_voice_message)
|
||||||
is EmoteMessageType -> "* $senderDisplayName ${messageType.body}"
|
is EmoteMessageType -> "* $senderDisambiguatedDisplayName ${messageType.body}"
|
||||||
is FileMessageType -> messageType.body
|
is FileMessageType -> messageType.body
|
||||||
is ImageMessageType -> messageType.body
|
is ImageMessageType -> messageType.body
|
||||||
is StickerMessageType -> messageType.body
|
is StickerMessageType -> messageType.body
|
||||||
|
|
@ -310,7 +310,7 @@ private fun buildNotifiableMessageEvent(
|
||||||
canBeReplaced: Boolean = false,
|
canBeReplaced: Boolean = false,
|
||||||
noisy: Boolean,
|
noisy: Boolean,
|
||||||
timestamp: Long,
|
timestamp: Long,
|
||||||
senderName: String?,
|
senderDisambiguatedDisplayName: String?,
|
||||||
body: String?,
|
body: String?,
|
||||||
// We cannot use Uri? type here, as that could trigger a
|
// We cannot use Uri? type here, as that could trigger a
|
||||||
// NotSerializableException when persisting this to storage
|
// NotSerializableException when persisting this to storage
|
||||||
|
|
@ -335,7 +335,7 @@ private fun buildNotifiableMessageEvent(
|
||||||
canBeReplaced = canBeReplaced,
|
canBeReplaced = canBeReplaced,
|
||||||
noisy = noisy,
|
noisy = noisy,
|
||||||
timestamp = timestamp,
|
timestamp = timestamp,
|
||||||
senderName = senderName,
|
senderDisambiguatedDisplayName = senderDisambiguatedDisplayName,
|
||||||
body = body,
|
body = body,
|
||||||
imageUriString = imageUriString,
|
imageUriString = imageUriString,
|
||||||
threadId = threadId,
|
threadId = threadId,
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ class RoomGroupMessageCreator @Inject constructor(
|
||||||
imageLoader: ImageLoader,
|
imageLoader: ImageLoader,
|
||||||
): RoomNotification.Message {
|
): RoomNotification.Message {
|
||||||
val lastKnownRoomEvent = events.last()
|
val lastKnownRoomEvent = events.last()
|
||||||
val roomName = lastKnownRoomEvent.roomName ?: lastKnownRoomEvent.senderName ?: "Room name (${roomId.value.take(8)}…)"
|
val roomName = lastKnownRoomEvent.roomName ?: lastKnownRoomEvent.senderDisambiguatedDisplayName ?: "Room name (${roomId.value.take(8)}…)"
|
||||||
val roomIsGroup = !lastKnownRoomEvent.roomIsDirect
|
val roomIsGroup = !lastKnownRoomEvent.roomIsDirect
|
||||||
val style = NotificationCompat.MessagingStyle(
|
val style = NotificationCompat.MessagingStyle(
|
||||||
Person.Builder()
|
Person.Builder()
|
||||||
|
|
@ -60,9 +60,9 @@ class RoomGroupMessageCreator @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
val tickerText = if (roomIsGroup) {
|
val tickerText = if (roomIsGroup) {
|
||||||
stringProvider.getString(R.string.notification_ticker_text_group, roomName, events.last().senderName, events.last().description)
|
stringProvider.getString(R.string.notification_ticker_text_group, roomName, events.last().senderDisambiguatedDisplayName, events.last().description)
|
||||||
} else {
|
} else {
|
||||||
stringProvider.getString(R.string.notification_ticker_text_dm, events.last().senderName, events.last().description)
|
stringProvider.getString(R.string.notification_ticker_text_dm, events.last().senderDisambiguatedDisplayName, events.last().description)
|
||||||
}
|
}
|
||||||
|
|
||||||
val largeBitmap = getRoomBitmap(events, imageLoader)
|
val largeBitmap = getRoomBitmap(events, imageLoader)
|
||||||
|
|
@ -108,7 +108,7 @@ class RoomGroupMessageCreator @Inject constructor(
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
Person.Builder()
|
Person.Builder()
|
||||||
.setName(event.senderName?.annotateForDebug(70))
|
.setName(event.senderDisambiguatedDisplayName?.annotateForDebug(70))
|
||||||
.setIcon(bitmapLoader.getUserIcon(event.senderAvatarPath, imageLoader))
|
.setIcon(bitmapLoader.getUserIcon(event.senderAvatarPath, imageLoader))
|
||||||
.setKey(event.senderId.value)
|
.setKey(event.senderId.value)
|
||||||
.build()
|
.build()
|
||||||
|
|
@ -152,7 +152,7 @@ class RoomGroupMessageCreator @Inject constructor(
|
||||||
private fun createFirstMessageSummaryLine(event: NotifiableMessageEvent, roomName: String, roomIsDirect: Boolean): CharSequence {
|
private fun createFirstMessageSummaryLine(event: NotifiableMessageEvent, roomName: String, roomIsDirect: Boolean): CharSequence {
|
||||||
return if (roomIsDirect) {
|
return if (roomIsDirect) {
|
||||||
buildSpannedString {
|
buildSpannedString {
|
||||||
event.senderName?.let {
|
event.senderDisambiguatedDisplayName?.let {
|
||||||
inSpans(StyleSpan(Typeface.BOLD)) {
|
inSpans(StyleSpan(Typeface.BOLD)) {
|
||||||
append(it)
|
append(it)
|
||||||
append(": ")
|
append(": ")
|
||||||
|
|
@ -165,7 +165,7 @@ class RoomGroupMessageCreator @Inject constructor(
|
||||||
inSpans(StyleSpan(Typeface.BOLD)) {
|
inSpans(StyleSpan(Typeface.BOLD)) {
|
||||||
append(roomName)
|
append(roomName)
|
||||||
append(": ")
|
append(": ")
|
||||||
event.senderName?.let {
|
event.senderDisambiguatedDisplayName?.let {
|
||||||
append(it)
|
append(it)
|
||||||
append(" ")
|
append(" ")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ data class NotifiableMessageEvent(
|
||||||
val senderId: UserId,
|
val senderId: UserId,
|
||||||
val noisy: Boolean,
|
val noisy: Boolean,
|
||||||
val timestamp: Long,
|
val timestamp: Long,
|
||||||
val senderName: String?,
|
val senderDisambiguatedDisplayName: String?,
|
||||||
val body: String?,
|
val body: String?,
|
||||||
// We cannot use Uri? type here, as that could trigger a
|
// We cannot use Uri? type here, as that could trigger a
|
||||||
// NotSerializableException when persisting this to storage
|
// NotSerializableException when persisting this to storage
|
||||||
|
|
@ -55,7 +55,6 @@ data class NotifiableMessageEvent(
|
||||||
) : NotifiableEvent {
|
) : NotifiableEvent {
|
||||||
val type: String = EventType.MESSAGE
|
val type: String = EventType.MESSAGE
|
||||||
override val description: String = body ?: ""
|
override val description: String = body ?: ""
|
||||||
val title: String = senderName ?: ""
|
|
||||||
|
|
||||||
// Example of value:
|
// Example of value:
|
||||||
// content://io.element.android.x.debug.notifications.fileprovider/downloads/temp/notif/matrix.org/XGItzSDOnSyXjYtOPfiKexDJ
|
// content://io.element.android.x.debug.notifications.fileprovider/downloads/temp/notif/matrix.org/XGItzSDOnSyXjYtOPfiKexDJ
|
||||||
|
|
|
||||||
|
|
@ -462,7 +462,7 @@ class NotifiableEventResolverTest {
|
||||||
senderId = A_USER_ID_2,
|
senderId = A_USER_ID_2,
|
||||||
noisy = false,
|
noisy = false,
|
||||||
timestamp = A_TIMESTAMP,
|
timestamp = A_TIMESTAMP,
|
||||||
senderName = null,
|
senderDisambiguatedDisplayName = null,
|
||||||
body = "Call in progress (unsupported)",
|
body = "Call in progress (unsupported)",
|
||||||
imageUriString = null,
|
imageUriString = null,
|
||||||
threadId = null,
|
threadId = null,
|
||||||
|
|
@ -586,7 +586,7 @@ class NotifiableEventResolverTest {
|
||||||
senderId = A_USER_ID_2,
|
senderId = A_USER_ID_2,
|
||||||
noisy = false,
|
noisy = false,
|
||||||
timestamp = A_TIMESTAMP,
|
timestamp = A_TIMESTAMP,
|
||||||
senderName = "Bob",
|
senderDisambiguatedDisplayName = "Bob",
|
||||||
body = body,
|
body = body,
|
||||||
imageUriString = null,
|
imageUriString = null,
|
||||||
threadId = null,
|
threadId = null,
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ fun aNotifiableMessageEvent(
|
||||||
editedEventId = null,
|
editedEventId = null,
|
||||||
noisy = false,
|
noisy = false,
|
||||||
timestamp = timestamp,
|
timestamp = timestamp,
|
||||||
senderName = "sender-name",
|
senderDisambiguatedDisplayName = "sender-name",
|
||||||
senderId = UserId("@sending-id:domain.com"),
|
senderId = UserId("@sending-id:domain.com"),
|
||||||
body = "message-body",
|
body = "message-body",
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue