Merge branch 'develop' into feature/fga/image_loading

This commit is contained in:
ganfra 2023-05-26 13:43:51 +02:00
commit c062d125ea
37 changed files with 163 additions and 70 deletions

1
changelog.d/464.feature Normal file
View file

@ -0,0 +1 @@
Display timestamps for text messages.

View file

@ -27,6 +27,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarData
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.MatrixTimeline import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
import io.element.android.libraries.matrix.api.timeline.item.event.EventSendState
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlin.random.Random import kotlin.random.Random
@ -49,7 +50,8 @@ internal fun aTimelineItemList(content: TimelineItemEventContent): ImmutableList
aTimelineItemEvent( aTimelineItemEvent(
isMine = false, isMine = false,
content = content, content = content,
groupPosition = TimelineItemGroupPosition.Middle groupPosition = TimelineItemGroupPosition.Middle,
sendState = EventSendState.SendingFailed("Message failed to send"),
), ),
aTimelineItemEvent( aTimelineItemEvent(
isMine = false, isMine = false,
@ -71,7 +73,8 @@ internal fun aTimelineItemList(content: TimelineItemEventContent): ImmutableList
aTimelineItemEvent( aTimelineItemEvent(
isMine = true, isMine = true,
content = content, content = content,
groupPosition = TimelineItemGroupPosition.Middle groupPosition = TimelineItemGroupPosition.Middle,
sendState = EventSendState.SendingFailed("Message failed to send"),
), ),
aTimelineItemEvent( aTimelineItemEvent(
isMine = true, isMine = true,
@ -88,14 +91,15 @@ internal fun aTimelineItemList(content: TimelineItemEventContent): ImmutableList
} }
internal fun aTimelineItemEvent( internal fun aTimelineItemEvent(
eventId: EventId = EventId("\$" + Random.nextInt().toString()),
isMine: Boolean = false, isMine: Boolean = false,
content: TimelineItemEventContent = aTimelineItemTextContent(), content: TimelineItemEventContent = aTimelineItemTextContent(),
groupPosition: TimelineItemGroupPosition = TimelineItemGroupPosition.First groupPosition: TimelineItemGroupPosition = TimelineItemGroupPosition.First,
sendState: EventSendState = EventSendState.Sent(eventId),
): TimelineItem.Event { ): TimelineItem.Event {
val randomId = "\$" + Random.nextInt().toString()
return TimelineItem.Event( return TimelineItem.Event(
id = randomId, id = eventId.value,
eventId = EventId(randomId), eventId = eventId,
senderId = UserId("@senderId:domain"), senderId = UserId("@senderId:domain"),
senderAvatar = AvatarData("@senderId:domain", "sender"), senderAvatar = AvatarData("@senderId:domain", "sender"),
content = content, content = content,
@ -104,8 +108,10 @@ internal fun aTimelineItemEvent(
AggregatedReaction("👍", "1") AggregatedReaction("👍", "1")
) )
), ),
sentTime = "12:34",
isMine = isMine, isMine = isMine,
senderDisplayName = "sender", senderDisplayName = "sender",
groupPosition = groupPosition, groupPosition = groupPosition,
sendState = sendState,
) )
} }

View file

@ -17,6 +17,7 @@
package io.element.android.features.messages.impl.timeline package io.element.android.features.messages.impl.timeline
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.BoxScope
@ -27,6 +28,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.layout.widthIn
@ -38,6 +40,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDownward import androidx.compose.material.icons.filled.ArrowDownward
import androidx.compose.material.icons.filled.Error
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@ -50,6 +53,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.LastBaseline import androidx.compose.ui.layout.LastBaseline
import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -67,18 +71,24 @@ import io.element.android.features.messages.impl.timeline.model.bubble.BubbleSta
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentProvider import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentProvider
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemDaySeparatorModel import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemDaySeparatorModel
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemLoadingModel import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemLoadingModel
import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.designsystem.ElementTextStyles
import io.element.android.libraries.designsystem.components.avatar.Avatar import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.ElementTheme
import io.element.android.libraries.designsystem.theme.components.FloatingActionButton import io.element.android.libraries.designsystem.theme.components.FloatingActionButton
import io.element.android.libraries.designsystem.theme.components.Icon 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.timeline.item.event.EventSendState
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import io.element.android.libraries.ui.strings.R as StringR
@Composable @Composable
fun TimelineView( fun TimelineView(
@ -261,12 +271,25 @@ fun TimelineItemEventRow(
.zIndex(-1f) .zIndex(-1f)
.widthIn(max = 320.dp) .widthIn(max = 320.dp)
) { ) {
TimelineItemEventContentView( Column {
content = event.content, TimelineItemEventContentView(
interactionSource = interactionSource, content = event.content,
onClick = onClick, interactionSource = interactionSource,
onLongClick = onLongClick, onClick = onClick,
) onLongClick = onLongClick,
)
TimestampView(
formattedTime = event.sentTime,
hasMessageSendingFailed = event.sendState is EventSendState.SendingFailed,
isMessageEdited = (event.content as? TimelineItemTextBasedContent)?.isEdited.orFalse(),
onClick = {
// TODO trigger either resending the message or opening the message edition history. This will be implemented later
},
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 4.dp)
.align(Alignment.End),
)
}
} }
TimelineItemReactionsView( TimelineItemReactionsView(
reactionsState = event.reactionsState, reactionsState = event.reactionsState,
@ -321,6 +344,36 @@ fun TimelineItemStateEventRow(
} }
} }
@Composable
private fun TimestampView(
formattedTime: String,
isMessageEdited: Boolean,
hasMessageSendingFailed: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
val tint = if (hasMessageSendingFailed) ElementTheme.colors.textActionCritical else null
Row(modifier = modifier.clickable(onClick = onClick)) {
if (isMessageEdited) {
Text(
stringResource(StringR.string.common_edited_suffix),
style = ElementTextStyles.Regular.caption2,
color = tint ?: MaterialTheme.colorScheme.secondary,
)
Spacer(modifier = Modifier.width(4.dp))
}
Text(
formattedTime,
style = ElementTextStyles.Regular.caption1,
color = tint ?: MaterialTheme.colorScheme.secondary,
)
if (hasMessageSendingFailed && tint != null) {
Spacer(modifier = Modifier.width(2.dp))
Icon(imageVector = Icons.Default.Error, contentDescription = "Error sending message", tint = tint, modifier = Modifier.size(15.dp, 18.dp))
}
}
}
@Composable @Composable
private fun MessageSenderInformation( private fun MessageSenderInformation(
sender: String, sender: String,

View file

@ -40,7 +40,8 @@ class TimelineItemContentMessageFactory @Inject constructor() {
return when (val messageType = content.type) { return when (val messageType = content.type) {
is EmoteMessageType -> TimelineItemEmoteContent( is EmoteMessageType -> TimelineItemEmoteContent(
body = messageType.body, body = messageType.body,
htmlDocument = messageType.formatted?.toHtmlDocument() htmlDocument = messageType.formatted?.toHtmlDocument(),
isEdited = content.isEdited,
) )
is ImageMessageType -> { is ImageMessageType -> {
val aspectRatio = aspectRatioOf(messageType.info?.width, messageType.info?.height) val aspectRatio = aspectRatioOf(messageType.info?.width, messageType.info?.height)
@ -77,11 +78,13 @@ class TimelineItemContentMessageFactory @Inject constructor() {
) )
is NoticeMessageType -> TimelineItemNoticeContent( is NoticeMessageType -> TimelineItemNoticeContent(
body = messageType.body, body = messageType.body,
htmlDocument = messageType.formatted?.toHtmlDocument() htmlDocument = messageType.formatted?.toHtmlDocument(),
isEdited = content.isEdited,
) )
is TextMessageType -> TimelineItemTextContent( is TextMessageType -> TimelineItemTextContent(
body = messageType.body, body = messageType.body,
htmlDocument = messageType.formatted?.toHtmlDocument() htmlDocument = messageType.formatted?.toHtmlDocument(),
isEdited = content.isEdited,
) )
else -> TimelineItemUnknownContent else -> TimelineItemUnknownContent
} }

View file

@ -23,8 +23,11 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItemReac
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.EventSendState
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import java.text.DateFormat
import java.util.Date
import javax.inject.Inject import javax.inject.Inject
class TimelineItemEventFactory @Inject constructor( class TimelineItemEventFactory @Inject constructor(
@ -55,6 +58,9 @@ class TimelineItemEventFactory @Inject constructor(
} }
} }
val timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT)
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 = senderDisplayName ?: currentSender.value,
@ -69,8 +75,10 @@ class TimelineItemEventFactory @Inject constructor(
senderAvatar = senderAvatarData, senderAvatar = senderAvatarData,
content = contentFactory.create(currentTimelineItem.event), content = contentFactory.create(currentTimelineItem.event),
isMine = currentTimelineItem.event.isOwn, isMine = currentTimelineItem.event.isOwn,
sentTime = sentTime,
groupPosition = groupPosition, groupPosition = groupPosition,
reactionsState = currentTimelineItem.computeReactionsState() reactionsState = currentTimelineItem.computeReactionsState(),
sendState = currentTimelineItem.event.localSendState ?: EventSendState.NotSentYet,
) )
} }

View file

@ -22,6 +22,7 @@ import io.element.android.features.messages.impl.timeline.model.virtual.Timeline
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
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.EventSendState
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
@Immutable @Immutable
@ -56,7 +57,8 @@ sealed interface TimelineItem {
val sentTime: String = "", val sentTime: String = "",
val isMine: Boolean = false, val isMine: Boolean = false,
val groupPosition: TimelineItemGroupPosition = TimelineItemGroupPosition.None, val groupPosition: TimelineItemGroupPosition = TimelineItemGroupPosition.None,
val reactionsState: TimelineItemReactions val reactionsState: TimelineItemReactions,
val sendState: EventSendState,
) : TimelineItem { ) : TimelineItem {
val showSenderInformation = groupPosition.isNew() && !isMine val showSenderInformation = groupPosition.isNew() && !isMine

View file

@ -20,7 +20,8 @@ import org.jsoup.nodes.Document
data class TimelineItemEmoteContent( data class TimelineItemEmoteContent(
override val body: String, override val body: String,
override val htmlDocument: Document? override val htmlDocument: Document?,
override val isEdited: Boolean,
) : TimelineItemTextBasedContent { ) : TimelineItemTextBasedContent {
override val type: String = "TimelineItemEmoteContent" override val type: String = "TimelineItemEmoteContent"
} }

View file

@ -32,6 +32,7 @@ class TimelineItemEventContentProvider : PreviewParameterProvider<TimelineItemEv
aTimelineItemRedactedContent(), aTimelineItemRedactedContent(),
aTimelineItemTextContent(), aTimelineItemTextContent(),
aTimelineItemUnknownContent(), aTimelineItemUnknownContent(),
aTimelineItemTextContent().copy(isEdited = true),
) )
} }
@ -48,7 +49,8 @@ class TimelineItemTextBasedContentProvider : PreviewParameterProvider<TimelineIt
fun aTimelineItemEmoteContent() = TimelineItemEmoteContent( fun aTimelineItemEmoteContent() = TimelineItemEmoteContent(
body = "Emote", body = "Emote",
htmlDocument = null htmlDocument = null,
isEdited = false,
) )
fun aTimelineItemEncryptedContent() = TimelineItemEncryptedContent( fun aTimelineItemEncryptedContent() = TimelineItemEncryptedContent(
@ -57,14 +59,16 @@ fun aTimelineItemEncryptedContent() = TimelineItemEncryptedContent(
fun aTimelineItemNoticeContent() = TimelineItemNoticeContent( fun aTimelineItemNoticeContent() = TimelineItemNoticeContent(
body = "Notice", body = "Notice",
htmlDocument = null htmlDocument = null,
isEdited = false,
) )
fun aTimelineItemRedactedContent() = TimelineItemRedactedContent fun aTimelineItemRedactedContent() = TimelineItemRedactedContent
fun aTimelineItemTextContent() = TimelineItemTextContent( fun aTimelineItemTextContent() = TimelineItemTextContent(
body = "Text", body = "Text",
htmlDocument = null htmlDocument = null,
isEdited = false,
) )
fun aTimelineItemUnknownContent() = TimelineItemUnknownContent fun aTimelineItemUnknownContent() = TimelineItemUnknownContent

View file

@ -20,7 +20,8 @@ import org.jsoup.nodes.Document
data class TimelineItemNoticeContent( data class TimelineItemNoticeContent(
override val body: String, override val body: String,
override val htmlDocument: Document? override val htmlDocument: Document?,
override val isEdited: Boolean,
) : TimelineItemTextBasedContent { ) : TimelineItemTextBasedContent {
override val type: String = "TimelineItemNoticeContent" override val type: String = "TimelineItemNoticeContent"
} }

View file

@ -21,4 +21,5 @@ import org.jsoup.nodes.Document
sealed interface TimelineItemTextBasedContent : TimelineItemEventContent { sealed interface TimelineItemTextBasedContent : TimelineItemEventContent {
val body: String val body: String
val htmlDocument: Document? val htmlDocument: Document?
val isEdited: Boolean
} }

View file

@ -20,7 +20,8 @@ import org.jsoup.nodes.Document
data class TimelineItemTextContent( data class TimelineItemTextContent(
override val body: String, override val body: String,
override val htmlDocument: Document? override val htmlDocument: Document?,
override val isEdited: Boolean,
) : TimelineItemTextBasedContent{ ) : TimelineItemTextBasedContent{
override val type: String = "TimelineItemTextContent" override val type: String = "TimelineItemTextContent"
} }

View file

@ -30,6 +30,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.matrix.api.timeline.item.event.EventSendState
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_MESSAGE import io.element.android.libraries.matrix.test.A_MESSAGE
import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID
@ -107,7 +108,7 @@ class ActionListPresenterTest {
val initialState = awaitItem() val initialState = awaitItem()
val messageEvent = aMessageEvent( val messageEvent = aMessageEvent(
isMine = false, isMine = false,
content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null) content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false)
) )
initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent)) initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent))
// val loadingState = awaitItem() // val loadingState = awaitItem()
@ -137,7 +138,7 @@ class ActionListPresenterTest {
val initialState = awaitItem() val initialState = awaitItem()
val messageEvent = aMessageEvent( val messageEvent = aMessageEvent(
isMine = true, isMine = true,
content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null) content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false)
) )
initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent)) initialState.eventSink.invoke(ActionListEvents.ComputeForMessage(messageEvent))
// val loadingState = awaitItem() // val loadingState = awaitItem()
@ -173,5 +174,6 @@ private fun aMessageEvent(
content = content, content = content,
sentTime = "", sentTime = "",
isMine = isMine, isMine = isMine,
reactionsState = TimelineItemReactions(persistentListOf()) reactionsState = TimelineItemReactions(persistentListOf()),
sendState = EventSendState.Sent(AN_EVENT_ID)
) )

View file

@ -21,6 +21,7 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItemReac
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.matrix.api.timeline.item.event.EventSendState
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_MESSAGE import io.element.android.libraries.matrix.test.A_MESSAGE
import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID
@ -29,7 +30,7 @@ import kotlinx.collections.immutable.persistentListOf
internal fun aMessageEvent( internal fun aMessageEvent(
isMine: Boolean = true, isMine: Boolean = true,
content: TimelineItemEventContent = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null), content: TimelineItemEventContent = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false),
) = TimelineItem.Event( ) = TimelineItem.Event(
id = AN_EVENT_ID.value, id = AN_EVENT_ID.value,
eventId = AN_EVENT_ID, eventId = AN_EVENT_ID,
@ -39,5 +40,6 @@ internal fun aMessageEvent(
content = content, content = content,
sentTime = "", sentTime = "",
isMine = isMine, isMine = isMine,
reactionsState = TimelineItemReactions(persistentListOf()) reactionsState = TimelineItemReactions(persistentListOf()),
sendState = EventSendState.Sent(AN_EVENT_ID)
) )

View file

@ -25,6 +25,7 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItemReac
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateEventContent
import io.element.android.features.messages.impl.timeline.model.virtual.aTimelineItemDaySeparatorModel import io.element.android.features.messages.impl.timeline.model.virtual.aTimelineItemDaySeparatorModel
import io.element.android.libraries.designsystem.components.avatar.anAvatarData import io.element.android.libraries.designsystem.components.avatar.anAvatarData
import io.element.android.libraries.matrix.api.timeline.item.event.EventSendState
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.AN_EVENT_ID_2 import io.element.android.libraries.matrix.test.AN_EVENT_ID_2
import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID
@ -40,7 +41,8 @@ class TimelineItemGrouperTest {
senderAvatar = anAvatarData(), senderAvatar = anAvatarData(),
senderDisplayName = "", senderDisplayName = "",
content = TimelineItemStateEventContent(body = "a state event"), content = TimelineItemStateEventContent(body = "a state event"),
reactionsState = TimelineItemReactions(emptyList<AggregatedReaction>().toImmutableList()) reactionsState = TimelineItemReactions(emptyList<AggregatedReaction>().toImmutableList()),
sendState = EventSendState.Sent(AN_EVENT_ID)
) )
private val aNonGroupableItem = aMessageEvent() private val aNonGroupableItem = aMessageEvent()
private val aNonGroupableItemNoEvent = TimelineItem.Virtual("virtual", aTimelineItemDaySeparatorModel("Today")) private val aNonGroupableItemNoEvent = TimelineItem.Virtual("virtual", aTimelineItemDaySeparatorModel("Today"))

View file

@ -32,7 +32,7 @@ class EventTimelineItemMapper(private val contentMapper: TimelineEventContentMap
fun map(eventTimelineItem: RustEventTimelineItem): EventTimelineItem = eventTimelineItem.use { fun map(eventTimelineItem: RustEventTimelineItem): EventTimelineItem = eventTimelineItem.use {
EventTimelineItem( EventTimelineItem(
uniqueIdentifier = it.uniqueIdentifier(), uniqueIdentifier = it.uniqueIdentifier(),
eventId = it.eventId()?.let { EventId(it) }, eventId = it.eventId()?.let(::EventId),
isEditable = it.isEditable(), isEditable = it.isEditable(),
isLocal = it.isLocal(), isLocal = it.isLocal(),
isOwn = it.isOwn(), isOwn = it.isOwn(),

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:b625f841a45111d58d76fd290cfad376a58e16265cc0b0d8e00318ffa1e3f48e oid sha256:8bd4c1be83610c41da8e95d5a2bcd141e513f62ca7223075256149b8c7bb9d25
size 35204 size 41915

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:a5391a08d36198d28cc2c05c83757d30dc207dd56ada9684cd3a3ea7f9812b0a oid sha256:180265714b5b0a370899468d9ba0f08e4e7d5d3af0721585ad579a643c00c04a
size 46977 size 53963

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:32ef3493e52faae7fa8c3dc1c2757212f3649c3dad151062d9fa6e5f49a541e7 oid sha256:b3ae864ab2a0856e73c6457dc12f9f7e59842befb5f3c983348c34cf70d4672d
size 192498 size 255

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:6ea74556d6594ce3805b59e5222480ca5a779704f6f358f5e227549d868bc3e3 oid sha256:deaebc55f67c36ecf75f0947868247425596f53866669f77d3cf0c55a0003632
size 192720 size 255

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:4b00e07786abd487a90069cb0fd3554cb1ebcda18ffb09cd879b6264365d7ade oid sha256:d981d2fa2ce67605954b388768c8587bc8c402ce9d7bf1a26d53a3354891f1eb
size 45245 size 254

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:8cda4043ba49b469e6e705333dc6bf37db379ab02cdbfd2adef416643d35b7a6 oid sha256:2c4cfe45d9cd9ab10134f664fd9bf18ac42de2d5f81acd7e2580f3f42b52bd3d
size 67214 size 254

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:6f951f69dd21d36338ddbfb303d50c554ef915c40e57919f699d83afce507d75 oid sha256:80021de1e90d971e486d7ee2c8e2e92124a044d98f85cdb1292e434bfcd5c9f9
size 36906 size 254

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:73de3dd7281ea437f3cb364cca175cec5379046da19fd8f1152f3a52f43b6bfa oid sha256:02f7a5ee81caf8fb81af1f2d5a4e98dfadf59e279a7814e177f657a68400110e
size 34442 size 41256

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:4bb36a52495fc17de86c0b66c6ac5eb8d4df64e3c512db41ec546b02c8157133 oid sha256:f761a4cb835fdf706588d33463989dca4fd944282a24c2e78cf4c166032d8b53
size 46507 size 53778

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:c88f3a942de1018f4bcaefe0e86147e7c7c67d67e31aa259ce76c186cac09632 oid sha256:eaeee0605ce741603cacd878cd970e15616f065247fce432dbf6fb4177e665ff
size 194017 size 255

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:01c7fa298c32e5459609cc0c8f3bd770986320b2595fcbdcc014e58d9fd15e51 oid sha256:c8c2a116793562fbf0b3987649f2c7d21a47524620c7f88d1b840e4c07bab828
size 194261 size 255

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:efaf767e5b45aad6bdbf54cc895b2f06c1cc1eb145a9644aa2e1d7d67f1060e5 oid sha256:b06f34095698894e909f967d16dec59353a77dc34899848212ab525de747ca65
size 44954 size 254

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:94bbbd907515d69854633be5e65bcf0e2891e146c269a04f0274bb35b016f72f oid sha256:2338ae31e82089a95863240fcf287551391ce8247b7726e344fb8a3c23e4b2bc
size 67916 size 254

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:b668eb7b9ce26c8d4b25d9e955ded21ef40c9db496a81cca99f299c84838fcd3 oid sha256:18ead89bcaa95b6d321ee8068f2690b3513d9bc35bab00de569f8924cbf5a3e8
size 36143 size 254

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:71ead784370bd7007dc52c48d31651512721c42fdcd37a177cb078802848412d oid sha256:49f7df48099566151474d1a3183dcc72359cf0b6a9bb5d38b15bd86ead6f9fde
size 43813 size 44390

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:e29a3b27b84b1be439b6b80e2a6df9ef30c87d74b51ca1079c683fd8d935d2c1 oid sha256:51f47e0b2ed979001dd76e440f8620f90ac42410999565a4341dad96bc5ecfbc
size 44308 size 44924

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:61ad59bb8d4cffe01fc8b0cd1b315b1129ca51185b3cfe3c730932b3052b6e5a oid sha256:d44b17653c344047225850811f3a5423fb3aca8c03a3925710c2e1df1a795d92
size 43556 size 254

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9d8cb1f4a11abbd47e86e575165e15e79f3e9385b7876e2348949a5553237b5f
size 40671

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:e03fa1605d99013550a1bfc705b04fd70fee8c620fee15bfabb1c2ed1829b042 oid sha256:dbdbec55388b60790188bf6d178b87cc52211cc1c5f62f3af8fe32bbe40ed6ae
size 42709 size 254

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:abf236791895e30e444122a59519334ef5b117f54ed45f15be694b64ba57e7e1 oid sha256:1ae6fe2834dc220fd474599e6aec1d43f18d35ca43924cb421d4db11b9fdb14f
size 43459 size 254

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:8d27d9bd487ad9d86da6ffc107c39d9bac96836e6a44c5a994e701c5df2535d7 oid sha256:d2a252bf1df88f74ec25847517d6fb10dc82c94724655ef5c6b982b2222962ad
size 41631 size 254

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ea5e469f454f50b88bc2d2860f3271119b1b85bacd8afe7210cb8ce38b44252c
size 40019