Timeline: map on background thread

This commit is contained in:
ganfra 2022-11-08 10:55:56 +01:00
parent 074da752ec
commit 754d266325
2 changed files with 79 additions and 52 deletions

View file

@ -0,0 +1,67 @@
package io.element.android.x.features.messages
import io.element.android.x.features.messages.model.MessagesItemGroupPosition
import io.element.android.x.features.messages.model.MessagesTimelineItemState
import io.element.android.x.matrix.core.UserId
import io.element.android.x.matrix.room.MatrixRoom
import io.element.android.x.matrix.timeline.MatrixTimelineItem
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.MessageType
class MessageTimelineItemStateMapper(
private val myUserId: UserId,
private val room: MatrixRoom,
private val dispatcher: CoroutineDispatcher,
) {
suspend fun map(timelineItems: List<MatrixTimelineItem>): List<MessagesTimelineItemState> =
withContext(dispatcher) {
val messagesTimelineItemState = ArrayList<MessagesTimelineItemState>()
for (index in timelineItems.indices.reversed()) {
val currentTimelineItem = timelineItems[index]
val timelineItemState = when (currentTimelineItem) {
is MatrixTimelineItem.Event -> {
val prevTimelineItem =
timelineItems.getOrNull(index - 1) as? MatrixTimelineItem.Event
val nextTimelineItem =
timelineItems.getOrNull(index + 1) as? MatrixTimelineItem.Event
val currentSender = currentTimelineItem.event.sender()
val previousSender = prevTimelineItem?.event?.sender()
val nextSender = nextTimelineItem?.event?.sender()
val groupPosition = when {
previousSender != currentSender && nextSender == currentSender -> MessagesItemGroupPosition.First
previousSender == currentSender && nextSender == currentSender -> MessagesItemGroupPosition.Middle
previousSender == currentSender && nextSender != currentSender -> MessagesItemGroupPosition.Last
else -> MessagesItemGroupPosition.None
}
val messageType =
currentTimelineItem.event.content().asMessage()?.msgtype()
val contentStr = when (messageType) {
is MessageType.Emote -> messageType.content.body
is MessageType.Image -> messageType.content.body
is MessageType.Notice -> messageType.content.body
is MessageType.Text -> messageType.content.body
null -> null
}
MessagesTimelineItemState.MessageEvent(
id = currentTimelineItem.event.eventId() ?: "",
sender = currentTimelineItem.event.sender(),
content = contentStr,
isMine = currentTimelineItem.event.isOwn(),
groupPosition = groupPosition
)
}
is MatrixTimelineItem.Virtual -> MessagesTimelineItemState.Virtual(
"virtual_item_$index"
)
MatrixTimelineItem.Other -> continue
}
messagesTimelineItemState.add(timelineItemState)
}
messagesTimelineItemState
}
}

View file

@ -5,19 +5,16 @@ import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.ViewModelContext
import io.element.android.x.designsystem.components.avatar.AvatarData
import io.element.android.x.designsystem.components.avatar.AvatarSize
import io.element.android.x.features.messages.model.MessagesItemGroupPosition
import io.element.android.x.features.messages.model.MessagesTimelineItemState
import io.element.android.x.features.messages.model.MessagesViewState
import io.element.android.x.matrix.MatrixClient
import io.element.android.x.matrix.MatrixInstance
import io.element.android.x.matrix.room.MatrixRoom
import io.element.android.x.matrix.timeline.MatrixTimeline
import io.element.android.x.matrix.timeline.MatrixTimelineItem
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import org.matrix.rustcomponents.sdk.MessageType
import org.matrix.rustcomponents.sdk.mediaSourceFromUrl
private const val PAGINATION_COUNT = 50
@ -26,6 +23,7 @@ class MessagesViewModel(
private val client: MatrixClient,
private val room: MatrixRoom,
private val timeline: MatrixTimeline,
private val messageTimelineItemStateMapper: MessageTimelineItemStateMapper,
private val initialState: MessagesViewState
) :
MavericksViewModel<MessagesViewState>(initialState) {
@ -39,7 +37,15 @@ class MessagesViewModel(
val matrix = MatrixInstance.getInstance()
val client = matrix.activeClient()
val room = client.getRoom(state.roomId) ?: return null
return MessagesViewModel(client, room, room.timeline(), state)
val messageTimelineItemStateMapper =
MessageTimelineItemStateMapper(client.userId(), room, Dispatchers.Default)
return MessagesViewModel(
client,
room,
room.timeline(),
messageTimelineItemStateMapper,
state
)
}
}
@ -67,53 +73,7 @@ class MessagesViewModel(
}.launchIn(viewModelScope)
timeline.timelineItems()
.map { timelineItems ->
val messagesTimelineItemState = ArrayList<MessagesTimelineItemState>()
for (index in timelineItems.indices.reversed()) {
val currentTimelineItem = timelineItems[index]
val timelineItemState = when (currentTimelineItem) {
is MatrixTimelineItem.Event -> {
val prevTimelineItem =
timelineItems.getOrNull(index - 1) as? MatrixTimelineItem.Event
val nextTimelineItem =
timelineItems.getOrNull(index + 1) as? MatrixTimelineItem.Event
val currentSender = currentTimelineItem.event.sender()
val previousSender = prevTimelineItem?.event?.sender()
val nextSender = nextTimelineItem?.event?.sender()
val groupPosition = when {
previousSender != currentSender && nextSender == currentSender -> MessagesItemGroupPosition.First
previousSender == currentSender && nextSender == currentSender -> MessagesItemGroupPosition.Middle
previousSender == currentSender && nextSender != currentSender -> MessagesItemGroupPosition.Last
else -> MessagesItemGroupPosition.None
}
val messageType =
currentTimelineItem.event.content().asMessage()?.msgtype()
val contentStr = when (messageType) {
is MessageType.Emote -> messageType.content.body
is MessageType.Image -> messageType.content.body
is MessageType.Notice -> messageType.content.body
is MessageType.Text -> messageType.content.body
null -> null
}
MessagesTimelineItemState.MessageEvent(
id = currentTimelineItem.event.eventId() ?: "",
sender = currentTimelineItem.event.sender(),
content = contentStr,
isMine = currentTimelineItem.event.sender() == client.userId().value,
groupPosition = groupPosition
)
}
is MatrixTimelineItem.Virtual -> MessagesTimelineItemState.Virtual(
"virtual_item_$index"
)
MatrixTimelineItem.Other -> continue
}
messagesTimelineItemState.add(timelineItemState)
}
messagesTimelineItemState
}
.map(messageTimelineItemStateMapper::map)
.execute {
copy(timelineItems = it)
}