Merge branch 'develop' into feature/fga/permalink_timeline
This commit is contained in:
commit
2c8abbed0c
1157 changed files with 4307 additions and 1899 deletions
|
|
@ -48,8 +48,11 @@ open class ActionListStateProvider : PreviewParameterProvider<ActionListState> {
|
|||
),
|
||||
anActionListState().copy(
|
||||
target = ActionListState.Target.Success(
|
||||
event = aTimelineItemEvent(content = aTimelineItemImageContent()).copy(
|
||||
reactionsState = reactionsState
|
||||
event = aTimelineItemEvent(
|
||||
content = aTimelineItemImageContent(),
|
||||
displayNameAmbiguous = true,
|
||||
).copy(
|
||||
reactionsState = reactionsState,
|
||||
),
|
||||
displayEmojiReactions = true,
|
||||
actions = aTimelineItemActionList(),
|
||||
|
|
@ -142,6 +145,7 @@ fun aTimelineItemActionList(): ImmutableList<TimelineItemAction> {
|
|||
TimelineItemAction.ViewSource,
|
||||
)
|
||||
}
|
||||
|
||||
fun aTimelineItemPollActionList(): ImmutableList<TimelineItemAction> {
|
||||
return persistentListOf(
|
||||
TimelineItemAction.EndPoll,
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ import androidx.compose.ui.unit.dp
|
|||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
|
||||
import io.element.android.features.messages.impl.sender.SenderName
|
||||
import io.element.android.features.messages.impl.sender.SenderNameMode
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
|
||||
|
|
@ -268,15 +270,11 @@ private fun MessageSummary(event: TimelineItem.Event, modifier: Modifier = Modif
|
|||
icon()
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Row {
|
||||
if (event.senderDisplayName != null) {
|
||||
Text(
|
||||
text = event.senderDisplayName,
|
||||
style = ElementTheme.typography.fontBodySmMedium,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
SenderName(
|
||||
senderId = event.senderId,
|
||||
senderProfile = event.senderProfile,
|
||||
senderNameMode = SenderNameMode.ActionList,
|
||||
)
|
||||
content()
|
||||
}
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ private fun RoomMemberSuggestionItemView(
|
|||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun MentionSuggestionsPickerView_Preview() {
|
||||
internal fun MentionSuggestionsPickerViewPreview() {
|
||||
ElementPreview {
|
||||
val roomMember = RoomMember(
|
||||
userId = UserId("@alice:server.org"),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (c) 2024 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.sender
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
||||
|
||||
// https://www.figma.com/file/Ni6Ii8YKtmXCKYNE90cC67/Timeline-(new)?type=design&node-id=917-80169&mode=design&t=A0CJCBbMqR8NOwUQ-0
|
||||
@Composable
|
||||
fun SenderName(
|
||||
senderId: UserId,
|
||||
senderProfile: ProfileTimelineDetails,
|
||||
senderNameMode: SenderNameMode,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
when (senderProfile) {
|
||||
is ProfileTimelineDetails.Error,
|
||||
ProfileTimelineDetails.Pending,
|
||||
ProfileTimelineDetails.Unavailable -> {
|
||||
MainText(text = senderId.value, mode = senderNameMode)
|
||||
}
|
||||
is ProfileTimelineDetails.Ready -> {
|
||||
val displayName = senderProfile.displayName
|
||||
if (displayName.isNullOrEmpty()) {
|
||||
MainText(text = senderId.value, mode = senderNameMode)
|
||||
} else {
|
||||
MainText(text = displayName, mode = senderNameMode)
|
||||
if (senderProfile.displayNameAmbiguous) {
|
||||
SecondaryText(text = senderId.value, mode = senderNameMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RowScope.MainText(
|
||||
text: String,
|
||||
mode: SenderNameMode,
|
||||
) {
|
||||
val style = when (mode) {
|
||||
is SenderNameMode.Timeline -> ElementTheme.typography.fontBodyMdMedium
|
||||
SenderNameMode.ActionList,
|
||||
SenderNameMode.Reply -> ElementTheme.typography.fontBodySmMedium
|
||||
}
|
||||
val modifier = when (mode) {
|
||||
is SenderNameMode.Timeline -> Modifier.alignByBaseline()
|
||||
SenderNameMode.ActionList,
|
||||
SenderNameMode.Reply -> Modifier
|
||||
}
|
||||
val color = when (mode) {
|
||||
is SenderNameMode.Timeline -> mode.mainColor
|
||||
SenderNameMode.ActionList,
|
||||
SenderNameMode.Reply -> MaterialTheme.colorScheme.primary
|
||||
}
|
||||
Text(
|
||||
modifier = modifier.clipToBounds(),
|
||||
text = text,
|
||||
style = style,
|
||||
color = color,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RowScope.SecondaryText(
|
||||
text: String,
|
||||
mode: SenderNameMode,
|
||||
) {
|
||||
val style = when (mode) {
|
||||
is SenderNameMode.Timeline -> ElementTheme.typography.fontBodySmRegular
|
||||
SenderNameMode.ActionList,
|
||||
SenderNameMode.Reply -> ElementTheme.typography.fontBodyXsRegular
|
||||
}
|
||||
val modifier = when (mode) {
|
||||
is SenderNameMode.Timeline -> Modifier.alignByBaseline()
|
||||
SenderNameMode.ActionList,
|
||||
SenderNameMode.Reply -> Modifier
|
||||
}
|
||||
Text(
|
||||
modifier = modifier.clipToBounds(),
|
||||
text = text,
|
||||
style = style,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun SenderNamePreview(
|
||||
@PreviewParameter(SenderNameDataProvider::class) senderNameData: SenderNameData,
|
||||
) = ElementPreview {
|
||||
SenderName(
|
||||
senderId = senderNameData.userId,
|
||||
senderProfile = senderNameData.profileTimelineDetails,
|
||||
senderNameMode = senderNameData.senderNameMode,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2024 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.sender
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.features.messages.impl.timeline.components.aProfileTimelineDetailsReady
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
||||
|
||||
data class SenderNameData(
|
||||
val userId: UserId,
|
||||
val profileTimelineDetails: ProfileTimelineDetails,
|
||||
val senderNameMode: SenderNameMode,
|
||||
)
|
||||
|
||||
open class SenderNameDataProvider : PreviewParameterProvider<SenderNameData> {
|
||||
override val values: Sequence<SenderNameData>
|
||||
get() = sequenceOf(
|
||||
SenderNameMode.Timeline(mainColor = Color.Red),
|
||||
SenderNameMode.Reply,
|
||||
SenderNameMode.ActionList,
|
||||
)
|
||||
.flatMap { senderNameMode ->
|
||||
sequenceOf(
|
||||
aSenderNameData(
|
||||
senderNameMode = senderNameMode,
|
||||
),
|
||||
aSenderNameData(
|
||||
senderNameMode = senderNameMode,
|
||||
displayNameAmbiguous = true,
|
||||
),
|
||||
SenderNameData(
|
||||
senderNameMode = senderNameMode,
|
||||
userId = UserId("@alice:${senderNameMode.javaClass.simpleName.lowercase()}"),
|
||||
profileTimelineDetails = ProfileTimelineDetails.Unavailable,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun aSenderNameData(
|
||||
senderNameMode: SenderNameMode,
|
||||
displayNameAmbiguous: Boolean = false,
|
||||
) = SenderNameData(
|
||||
userId = UserId("@alice:${senderNameMode.javaClass.simpleName.lowercase()}"),
|
||||
profileTimelineDetails = aProfileTimelineDetailsReady(
|
||||
displayName = "Alice ${senderNameMode.javaClass.simpleName}",
|
||||
displayNameAmbiguous = displayNameAmbiguous,
|
||||
),
|
||||
senderNameMode = senderNameMode,
|
||||
)
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2024 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.sender
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
sealed interface SenderNameMode {
|
||||
data class Timeline(val mainColor: Color) : SenderNameMode
|
||||
data object Reply : SenderNameMode
|
||||
data object ActionList : SenderNameMode
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package io.element.android.features.messages.impl.timeline
|
||||
|
||||
import io.element.android.features.messages.impl.timeline.components.aProfileTimelineDetailsReady
|
||||
import io.element.android.features.messages.impl.timeline.components.receipt.aReadReceiptData
|
||||
import io.element.android.features.messages.impl.timeline.model.InReplyToDetails
|
||||
import io.element.android.features.messages.impl.timeline.model.NewEventState
|
||||
|
|
@ -130,6 +131,7 @@ internal fun aTimelineItemEvent(
|
|||
isMine: Boolean = false,
|
||||
isEditable: Boolean = false,
|
||||
senderDisplayName: String = "Sender",
|
||||
displayNameAmbiguous: Boolean = false,
|
||||
content: TimelineItemEventContent = aTimelineItemTextContent(),
|
||||
groupPosition: TimelineItemGroupPosition = TimelineItemGroupPosition.None,
|
||||
sendState: LocalEventSendState? = null,
|
||||
|
|
@ -151,7 +153,10 @@ internal fun aTimelineItemEvent(
|
|||
sentTime = "12:34",
|
||||
isMine = isMine,
|
||||
isEditable = isEditable,
|
||||
senderDisplayName = senderDisplayName,
|
||||
senderProfile = aProfileTimelineDetailsReady(
|
||||
displayName = senderDisplayName,
|
||||
displayNameAmbiguous = displayNameAmbiguous,
|
||||
),
|
||||
groupPosition = groupPosition,
|
||||
localSendState = sendState,
|
||||
inReplyTo = inReplyTo,
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ internal fun MessagesReactionButtonPreview(@PreviewParameter(AggregatedReactionP
|
|||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun MessagesAddReactionButtonPreview() = ElementPreview {
|
||||
internal fun MessagesReactionButtonAddPreview() = ElementPreview {
|
||||
MessagesReactionButton(
|
||||
content = MessagesReactionsButtonContent.Icon(CompoundDrawables.ic_compound_reaction_add),
|
||||
onClick = {},
|
||||
|
|
@ -201,7 +201,7 @@ internal fun MessagesAddReactionButtonPreview() = ElementPreview {
|
|||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun MessagesReactionExtraButtonsPreview() = ElementPreview {
|
||||
internal fun MessagesReactionButtonExtraPreview() = ElementPreview {
|
||||
Row {
|
||||
MessagesReactionButton(
|
||||
content = MessagesReactionsButtonContent.Text("12 more"),
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ import androidx.constraintlayout.compose.ConstrainScope
|
|||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.features.messages.impl.sender.SenderName
|
||||
import io.element.android.features.messages.impl.sender.SenderNameMode
|
||||
import io.element.android.features.messages.impl.timeline.TimelineEvents
|
||||
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
|
||||
|
|
@ -106,6 +108,8 @@ import io.element.android.libraries.designsystem.theme.components.Icon
|
|||
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.UserId
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
||||
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.testtags.TestTags
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
|
@ -291,7 +295,8 @@ private fun TimelineItemEventRowContent(
|
|||
val avatarStrokeSize = 3.dp
|
||||
if (event.showSenderInformation && !timelineRoomInfo.isDm) {
|
||||
MessageSenderInformation(
|
||||
event.safeSenderName,
|
||||
event.senderId,
|
||||
event.senderProfile,
|
||||
event.senderAvatar,
|
||||
avatarStrokeSize,
|
||||
Modifier
|
||||
|
|
@ -371,7 +376,8 @@ private fun TimelineItemEventRowContent(
|
|||
|
||||
@Composable
|
||||
private fun MessageSenderInformation(
|
||||
sender: String,
|
||||
senderId: UserId,
|
||||
senderProfile: ProfileTimelineDetails,
|
||||
senderAvatar: AvatarData,
|
||||
avatarStrokeSize: Dp,
|
||||
modifier: Modifier = Modifier
|
||||
|
|
@ -398,13 +404,10 @@ private fun MessageSenderInformation(
|
|||
Row {
|
||||
Avatar(senderAvatar)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
modifier = Modifier.clipToBounds(),
|
||||
text = sender,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = avatarColors.foreground,
|
||||
style = ElementTheme.typography.fontBodyMdMedium,
|
||||
SenderName(
|
||||
senderId = senderId,
|
||||
senderProfile = senderProfile,
|
||||
senderNameMode = SenderNameMode.Timeline(avatarColors.foreground),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -561,10 +564,10 @@ private fun MessageEventBubbleContent(
|
|||
}
|
||||
}
|
||||
val inReplyTo = @Composable { inReplyTo: InReplyToDetails ->
|
||||
val senderName = inReplyTo.senderDisplayName ?: inReplyTo.senderId.value
|
||||
val topPadding = if (showThreadDecoration) 0.dp else 8.dp
|
||||
ReplyToContent(
|
||||
senderName = senderName,
|
||||
senderId = inReplyTo.senderId,
|
||||
senderProfile = inReplyTo.senderProfile,
|
||||
metadata = inReplyTo.metadata(),
|
||||
modifier = Modifier
|
||||
.padding(top = topPadding, start = 8.dp, end = 8.dp)
|
||||
|
|
@ -609,7 +612,8 @@ private fun MessageEventBubbleContent(
|
|||
|
||||
@Composable
|
||||
private fun ReplyToContent(
|
||||
senderName: String,
|
||||
senderId: UserId,
|
||||
senderProfile: ProfileTimelineDetails,
|
||||
metadata: InReplyToMetadata?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
|
@ -633,18 +637,15 @@ private fun ReplyToContent(
|
|||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
}
|
||||
val a11InReplyToText = stringResource(CommonStrings.common_in_reply_to, senderName)
|
||||
val a11InReplyToText = stringResource(CommonStrings.common_in_reply_to, senderProfile.getDisambiguatedDisplayName(senderId))
|
||||
Column(verticalArrangement = Arrangement.SpaceBetween) {
|
||||
Text(
|
||||
SenderName(
|
||||
senderId = senderId,
|
||||
senderProfile = senderProfile,
|
||||
senderNameMode = SenderNameMode.Reply,
|
||||
modifier = Modifier.semantics {
|
||||
contentDescription = a11InReplyToText
|
||||
},
|
||||
text = senderName,
|
||||
style = ElementTheme.typography.fontBodySmMedium,
|
||||
textAlign = TextAlign.Start,
|
||||
color = ElementTheme.materialColors.primary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
ReplyToContentText(metadata)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2024 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.timeline.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import io.element.android.features.messages.impl.timeline.model.InReplyToDetails
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TimelineItemEventRowDisambiguatedPreview(
|
||||
@PreviewParameter(InReplyToDetailsDisambiguatedProvider::class) inReplyToDetails: InReplyToDetails,
|
||||
) = ElementPreview {
|
||||
TimelineItemEventRowWithReplyContentToPreview(
|
||||
inReplyToDetails = inReplyToDetails,
|
||||
displayNameAmbiguous = true,
|
||||
)
|
||||
}
|
||||
|
||||
class InReplyToDetailsDisambiguatedProvider : InReplyToDetailsProvider() {
|
||||
override val values: Sequence<InReplyToDetails>
|
||||
get() = sequenceOf(
|
||||
aMessageContent(
|
||||
body = "Message which are being replied.",
|
||||
type = TextMessageType("Message which are being replied.", null)
|
||||
),
|
||||
).map {
|
||||
aInReplyToDetails(
|
||||
displayNameAmbiguous = true,
|
||||
eventContent = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,6 @@ internal fun TimelineItemEventRowTimestampPreview(
|
|||
body = str,
|
||||
),
|
||||
reactionsState = aTimelineItemReactions(count = 0),
|
||||
senderDisplayName = "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.NoticeMessageType
|
||||
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.TextMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||
|
|
@ -58,7 +59,10 @@ internal fun TimelineItemEventRowWithReplyPreview(
|
|||
}
|
||||
|
||||
@Composable
|
||||
internal fun TimelineItemEventRowWithReplyContentToPreview(inReplyToDetails: InReplyToDetails) {
|
||||
internal fun TimelineItemEventRowWithReplyContentToPreview(
|
||||
inReplyToDetails: InReplyToDetails,
|
||||
displayNameAmbiguous: Boolean = false,
|
||||
) {
|
||||
Column {
|
||||
sequenceOf(false, true).forEach {
|
||||
ATimelineItemEventRow(
|
||||
|
|
@ -69,6 +73,7 @@ internal fun TimelineItemEventRowWithReplyContentToPreview(inReplyToDetails: InR
|
|||
body = "A reply."
|
||||
),
|
||||
inReplyTo = inReplyToDetails,
|
||||
displayNameAmbiguous = displayNameAmbiguous,
|
||||
groupPosition = TimelineItemGroupPosition.First,
|
||||
),
|
||||
)
|
||||
|
|
@ -80,6 +85,7 @@ internal fun TimelineItemEventRowWithReplyContentToPreview(inReplyToDetails: InR
|
|||
aspectRatio = 2.5f
|
||||
),
|
||||
inReplyTo = inReplyToDetails,
|
||||
displayNameAmbiguous = displayNameAmbiguous,
|
||||
isThreaded = true,
|
||||
groupPosition = TimelineItemGroupPosition.Last,
|
||||
),
|
||||
|
|
@ -150,7 +156,7 @@ open class InReplyToDetailsProvider : PreviewParameterProvider<InReplyToDetails>
|
|||
)
|
||||
}
|
||||
|
||||
private fun aMessageContent(
|
||||
protected fun aMessageContent(
|
||||
body: String,
|
||||
type: MessageType,
|
||||
) = MessageContent(
|
||||
|
|
@ -163,12 +169,24 @@ open class InReplyToDetailsProvider : PreviewParameterProvider<InReplyToDetails>
|
|||
|
||||
protected fun aInReplyToDetails(
|
||||
eventContent: EventContent,
|
||||
displayNameAmbiguous: Boolean = false,
|
||||
) = InReplyToDetails(
|
||||
eventId = EventId("\$event"),
|
||||
eventContent = eventContent,
|
||||
senderId = UserId("@Sender:domain"),
|
||||
senderDisplayName = "Sender",
|
||||
senderAvatarUrl = null,
|
||||
senderProfile = aProfileTimelineDetailsReady(
|
||||
displayNameAmbiguous = displayNameAmbiguous,
|
||||
),
|
||||
textContent = (eventContent as? MessageContent)?.body.orEmpty(),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun aProfileTimelineDetailsReady(
|
||||
displayName: String? = "Sender",
|
||||
displayNameAmbiguous: Boolean = false,
|
||||
avatarUrl: String? = null,
|
||||
) = ProfileTimelineDetails.Ready(
|
||||
displayName = displayName,
|
||||
displayNameAmbiguous = displayNameAmbiguous,
|
||||
avatarUrl = avatarUrl,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ private fun computeReceiptDescription(receipts: ImmutableList<ReadReceiptData>):
|
|||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TimelineItemReactionsViewPreview(
|
||||
internal fun TimelineItemReadReceiptViewPreview(
|
||||
@PreviewParameter(ReadReceiptViewStateProvider::class) state: ReadReceiptViewState,
|
||||
) = ElementPreview {
|
||||
TimelineItemReadReceiptView(
|
||||
|
|
|
|||
|
|
@ -52,8 +52,12 @@ class TimelineItemContentFactory @Inject constructor(
|
|||
is FailedToParseMessageLikeContent -> failedToParseMessageFactory.create(itemContent)
|
||||
is FailedToParseStateContent -> failedToParseStateFactory.create(itemContent)
|
||||
is MessageContent -> {
|
||||
val senderDisplayName = eventTimelineItem.senderProfile.getDisambiguatedDisplayName(eventTimelineItem.sender)
|
||||
messageFactory.create(itemContent, senderDisplayName, eventTimelineItem.eventId)
|
||||
val senderDisambiguatedDisplayName = eventTimelineItem.senderProfile.getDisambiguatedDisplayName(eventTimelineItem.sender)
|
||||
messageFactory.create(
|
||||
content = itemContent,
|
||||
senderDisambiguatedDisplayName = senderDisambiguatedDisplayName,
|
||||
eventId = eventTimelineItem.eventId,
|
||||
)
|
||||
}
|
||||
is ProfileChangeContent -> profileChangeFactory.create(eventTimelineItem)
|
||||
is RedactedContent -> redactedMessageFactory.create(itemContent)
|
||||
|
|
|
|||
|
|
@ -70,17 +70,21 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
|||
private val htmlConverterProvider: HtmlConverterProvider,
|
||||
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) {
|
||||
is EmoteMessageType -> {
|
||||
val emoteBody = "* $senderDisplayName ${messageType.body.trimEnd()}"
|
||||
val emoteBody = "* $senderDisambiguatedDisplayName ${messageType.body.trimEnd()}"
|
||||
TimelineItemEmoteContent(
|
||||
body = emoteBody,
|
||||
htmlDocument = messageType.formatted?.toHtmlDocument(
|
||||
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,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
|
|||
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.getAvatarUrl
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import java.text.DateFormat
|
||||
|
|
@ -55,15 +55,14 @@ class TimelineItemEventFactory @Inject constructor(
|
|||
val currentSender = currentTimelineItem.event.sender
|
||||
val groupPosition =
|
||||
computeGroupPosition(currentTimelineItem, timelineItems, index)
|
||||
val (senderDisplayName, senderAvatarUrl) = currentTimelineItem.getSenderInfo()
|
||||
|
||||
val senderProfile = currentTimelineItem.event.senderProfile
|
||||
val timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT)
|
||||
val sentTime = timeFormatter.format(Date(currentTimelineItem.event.timestamp))
|
||||
|
||||
val senderAvatarData = AvatarData(
|
||||
id = currentSender.value,
|
||||
name = senderDisplayName ?: currentSender.value,
|
||||
url = senderAvatarUrl,
|
||||
name = senderProfile.getDisambiguatedDisplayName(currentSender),
|
||||
url = senderProfile.getAvatarUrl(),
|
||||
size = AvatarSize.TimelineSender
|
||||
)
|
||||
currentTimelineItem.event
|
||||
|
|
@ -72,7 +71,7 @@ class TimelineItemEventFactory @Inject constructor(
|
|||
eventId = currentTimelineItem.eventId,
|
||||
transactionId = currentTimelineItem.transactionId,
|
||||
senderId = currentSender,
|
||||
senderDisplayName = senderDisplayName,
|
||||
senderProfile = senderProfile,
|
||||
senderAvatar = senderAvatarData,
|
||||
content = contentFactory.create(currentTimelineItem.event),
|
||||
isMine = currentTimelineItem.event.isOwn,
|
||||
|
|
@ -99,26 +98,6 @@ class TimelineItemEventFactory @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun MatrixTimelineItem.Event.getSenderInfo(): Pair<String?, String?> {
|
||||
val senderDisplayName: String?
|
||||
val senderAvatarUrl: String?
|
||||
|
||||
when (val senderProfile = event.senderProfile) {
|
||||
ProfileTimelineDetails.Unavailable,
|
||||
ProfileTimelineDetails.Pending,
|
||||
is ProfileTimelineDetails.Error -> {
|
||||
senderDisplayName = null
|
||||
senderAvatarUrl = null
|
||||
}
|
||||
is ProfileTimelineDetails.Ready -> {
|
||||
senderDisplayName = senderProfile.getDisambiguatedDisplayName(event.sender)
|
||||
senderAvatarUrl = senderProfile.avatarUrl
|
||||
}
|
||||
}
|
||||
|
||||
return senderDisplayName to senderAvatarUrl
|
||||
}
|
||||
|
||||
private fun MatrixTimelineItem.Event.computeReactionsState(): TimelineItemReactions {
|
||||
val timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT)
|
||||
var aggregatedReactions = event.reactions.map { reaction ->
|
||||
|
|
|
|||
|
|
@ -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.InReplyTo
|
||||
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.TextMessageType
|
||||
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(
|
||||
val eventId: EventId,
|
||||
val senderId: UserId,
|
||||
val senderDisplayName: String?,
|
||||
val senderAvatarUrl: String?,
|
||||
val senderProfile: ProfileTimelineDetails,
|
||||
val eventContent: EventContent?,
|
||||
val textContent: String?,
|
||||
)
|
||||
|
|
@ -41,8 +41,7 @@ fun InReplyTo.map(
|
|||
is InReplyTo.Ready -> InReplyToDetails(
|
||||
eventId = eventId,
|
||||
senderId = senderId,
|
||||
senderDisplayName = senderDisplayName,
|
||||
senderAvatarUrl = senderAvatarUrl,
|
||||
senderProfile = senderProfile,
|
||||
eventContent = content,
|
||||
textContent = when (content) {
|
||||
is MessageContent -> {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ import io.element.android.libraries.matrix.api.core.TransactionId
|
|||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Immutable
|
||||
|
|
@ -65,7 +67,7 @@ sealed interface TimelineItem {
|
|||
val eventId: EventId? = null,
|
||||
val transactionId: TransactionId? = null,
|
||||
val senderId: UserId,
|
||||
val senderDisplayName: String?,
|
||||
val senderProfile: ProfileTimelineDetails,
|
||||
val senderAvatar: AvatarData,
|
||||
val content: TimelineItemEventContent,
|
||||
val sentTime: String = "",
|
||||
|
|
@ -82,7 +84,7 @@ sealed interface TimelineItem {
|
|||
) : TimelineItem {
|
||||
val showSenderInformation = groupPosition.isNew() && !isMine
|
||||
|
||||
val safeSenderName: String = senderDisplayName ?: senderId.value
|
||||
val safeSenderName: String = senderProfile.getDisambiguatedDisplayName(senderId)
|
||||
|
||||
val failedToSend: Boolean = localSendState is LocalEventSendState.SendingFailed
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package io.element.android.features.messages.impl.fixtures
|
|||
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemDebugInfo
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemReactions
|
||||
import io.element.android.features.messages.impl.timeline.components.aProfileTimelineDetailsReady
|
||||
import io.element.android.features.messages.impl.timeline.model.InReplyToDetails
|
||||
import io.element.android.features.messages.impl.timeline.model.ReadReceiptData
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||
|
|
@ -48,7 +49,7 @@ internal fun aMessageEvent(
|
|||
id = eventId?.value.orEmpty(),
|
||||
eventId = eventId,
|
||||
senderId = A_USER_ID,
|
||||
senderDisplayName = A_USER_NAME,
|
||||
senderProfile = aProfileTimelineDetailsReady(displayName = A_USER_NAME),
|
||||
senderAvatar = AvatarData(A_USER_ID.value, A_USER_NAME, size = AvatarSize.TimelineSender),
|
||||
content = content,
|
||||
sentTime = "",
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = OtherMessageType(msgType = "a_type", body = "body")),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemTextContent(
|
||||
|
|
@ -100,7 +100,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = LocationMessageType("body", "geo:1,2", "description")),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemLocationContent(
|
||||
|
|
@ -116,7 +116,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = LocationMessageType("body", "", null)),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemTextContent(
|
||||
|
|
@ -134,7 +134,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = TextMessageType("body", null)),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemTextContent(
|
||||
|
|
@ -152,7 +152,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = TextMessageType("https://www.example.org", null)),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
) as TimelineItemTextContent
|
||||
val expected = TimelineItemTextContent(
|
||||
|
|
@ -200,7 +200,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
formatted = FormattedBody(MessageFormat.HTML, expected.toString())
|
||||
)
|
||||
),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
assertThat((result as TimelineItemTextContent).formattedBody).isEqualTo(expected)
|
||||
|
|
@ -218,7 +218,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
formatted = FormattedBody(MessageFormat.UNKNOWN, "formatted")
|
||||
)
|
||||
),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
assertThat((result as TimelineItemTextContent).formattedBody).isNull()
|
||||
|
|
@ -229,7 +229,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = VideoMessageType("body", null, null, MediaSource("url"), null)),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemVideoContent(
|
||||
|
|
@ -277,7 +277,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
),
|
||||
)
|
||||
),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemVideoContent(
|
||||
|
|
@ -303,7 +303,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = AudioMessageType("body", MediaSource("url"), null)),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemAudioContent(
|
||||
|
|
@ -332,7 +332,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
)
|
||||
)
|
||||
),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemAudioContent(
|
||||
|
|
@ -351,7 +351,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = VoiceMessageType("body", MediaSource("url"), null, null)),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemVoiceContent(
|
||||
|
|
@ -384,7 +384,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
),
|
||||
)
|
||||
),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemVoiceContent(
|
||||
|
|
@ -409,7 +409,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
)
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = VoiceMessageType("body", MediaSource("url"), null, null)),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemAudioContent(
|
||||
|
|
@ -428,7 +428,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = ImageMessageType("body", null, null, MediaSource("url"), null)),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemImageContent(
|
||||
|
|
@ -499,7 +499,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
)
|
||||
)
|
||||
),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemImageContent(
|
||||
|
|
@ -524,7 +524,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = FileMessageType("body", MediaSource("url"), null)),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemFileContent(
|
||||
|
|
@ -559,7 +559,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
)
|
||||
)
|
||||
),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemFileContent(
|
||||
|
|
@ -578,7 +578,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = NoticeMessageType("body", null)),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemNoticeContent(
|
||||
|
|
@ -601,7 +601,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
formatted = FormattedBody(MessageFormat.HTML, "formatted")
|
||||
)
|
||||
),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
assertThat((result as TimelineItemNoticeContent).formattedBody).isEqualTo("formatted")
|
||||
|
|
@ -612,7 +612,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
val sut = createTimelineItemContentMessageFactory()
|
||||
val result = sut.create(
|
||||
content = createMessageContent(type = EmoteMessageType("body", null)),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
val expected = TimelineItemEmoteContent(
|
||||
|
|
@ -635,7 +635,7 @@ class TimelineItemContentMessageFactoryTest {
|
|||
formatted = FormattedBody(MessageFormat.HTML, "formatted")
|
||||
)
|
||||
),
|
||||
senderDisplayName = "Bob",
|
||||
senderDisambiguatedDisplayName = "Bob",
|
||||
eventId = AN_EVENT_ID,
|
||||
)
|
||||
assertThat((result as TimelineItemEmoteContent).formattedBody).isEqualTo(SpannableString("* Bob formatted"))
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.google.common.truth.Truth.assertThat
|
|||
import io.element.android.features.messages.impl.fixtures.aMessageEvent
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemDebugInfo
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemReactions
|
||||
import io.element.android.features.messages.impl.timeline.components.aProfileTimelineDetailsReady
|
||||
import io.element.android.features.messages.impl.timeline.model.ReadReceiptData
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItemReadReceipts
|
||||
|
|
@ -39,7 +40,7 @@ class TimelineItemGrouperTest {
|
|||
id = "0",
|
||||
senderId = A_USER_ID,
|
||||
senderAvatar = anAvatarData(),
|
||||
senderDisplayName = "",
|
||||
senderProfile = aProfileTimelineDetailsReady(displayName = ""),
|
||||
content = TimelineItemStateEventContent(body = "a state event"),
|
||||
reactionsState = aTimelineItemReactions(count = 0),
|
||||
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.A_USER_ID
|
||||
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
||||
import io.element.android.libraries.matrix.test.timeline.aProfileTimelineDetails
|
||||
import org.junit.Test
|
||||
|
||||
class InReplyToDetailTest {
|
||||
|
|
@ -54,8 +55,7 @@ class InReplyToDetailTest {
|
|||
val inReplyTo = InReplyTo.Ready(
|
||||
eventId = AN_EVENT_ID,
|
||||
senderId = A_USER_ID,
|
||||
senderDisplayName = "senderDisplayName",
|
||||
senderAvatarUrl = "senderAvatarUrl",
|
||||
senderProfile = aProfileTimelineDetails(),
|
||||
content = RoomMembershipContent(
|
||||
userId = A_USER_ID,
|
||||
change = MembershipChange.INVITED,
|
||||
|
|
@ -73,8 +73,7 @@ class InReplyToDetailTest {
|
|||
val inReplyTo = InReplyTo.Ready(
|
||||
eventId = AN_EVENT_ID,
|
||||
senderId = A_USER_ID,
|
||||
senderDisplayName = "senderDisplayName",
|
||||
senderAvatarUrl = "senderAvatarUrl",
|
||||
senderProfile = aProfileTimelineDetails(),
|
||||
content = MessageContent(
|
||||
body = "**Hello!**",
|
||||
inReplyTo = null,
|
||||
|
|
@ -101,8 +100,7 @@ class InReplyToDetailTest {
|
|||
val inReplyTo = InReplyTo.Ready(
|
||||
eventId = AN_EVENT_ID,
|
||||
senderId = A_USER_ID,
|
||||
senderDisplayName = "senderDisplayName",
|
||||
senderAvatarUrl = "senderAvatarUrl",
|
||||
senderProfile = aProfileTimelineDetails(),
|
||||
content = MessageContent(
|
||||
body = "**Hello!**",
|
||||
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.OtherState
|
||||
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.RoomMembershipContent
|
||||
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.timeline.aMessageContent
|
||||
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.AttachmentThumbnailInfo
|
||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
|
||||
|
|
@ -430,15 +432,13 @@ class InReplyToMetadataKtTest {
|
|||
fun anInReplyToDetails(
|
||||
eventId: EventId = AN_EVENT_ID,
|
||||
senderId: UserId = A_USER_ID,
|
||||
senderDisplayName: String? = "senderDisplayName",
|
||||
senderAvatarUrl: String? = "senderAvatarUrl",
|
||||
senderProfile: ProfileTimelineDetails = aProfileTimelineDetails(),
|
||||
eventContent: EventContent? = aMessageContent(),
|
||||
textContent: String? = "textContent",
|
||||
) = InReplyToDetails(
|
||||
eventId = eventId,
|
||||
senderId = senderId,
|
||||
senderDisplayName = senderDisplayName,
|
||||
senderAvatarUrl = senderAvatarUrl,
|
||||
senderProfile = senderProfile,
|
||||
eventContent = eventContent,
|
||||
textContent = textContent,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue