Timeline: map on background thread
This commit is contained in:
parent
a69549bbfc
commit
8b10c61704
2 changed files with 79 additions and 52 deletions
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -5,19 +5,16 @@ import com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarSize
|
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.features.messages.model.MessagesViewState
|
||||||
import io.element.android.x.matrix.MatrixClient
|
import io.element.android.x.matrix.MatrixClient
|
||||||
import io.element.android.x.matrix.MatrixInstance
|
import io.element.android.x.matrix.MatrixInstance
|
||||||
import io.element.android.x.matrix.room.MatrixRoom
|
import io.element.android.x.matrix.room.MatrixRoom
|
||||||
import io.element.android.x.matrix.timeline.MatrixTimeline
|
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.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.rustcomponents.sdk.MessageType
|
|
||||||
import org.matrix.rustcomponents.sdk.mediaSourceFromUrl
|
import org.matrix.rustcomponents.sdk.mediaSourceFromUrl
|
||||||
|
|
||||||
private const val PAGINATION_COUNT = 50
|
private const val PAGINATION_COUNT = 50
|
||||||
|
|
@ -26,6 +23,7 @@ class MessagesViewModel(
|
||||||
private val client: MatrixClient,
|
private val client: MatrixClient,
|
||||||
private val room: MatrixRoom,
|
private val room: MatrixRoom,
|
||||||
private val timeline: MatrixTimeline,
|
private val timeline: MatrixTimeline,
|
||||||
|
private val messageTimelineItemStateMapper: MessageTimelineItemStateMapper,
|
||||||
private val initialState: MessagesViewState
|
private val initialState: MessagesViewState
|
||||||
) :
|
) :
|
||||||
MavericksViewModel<MessagesViewState>(initialState) {
|
MavericksViewModel<MessagesViewState>(initialState) {
|
||||||
|
|
@ -39,7 +37,15 @@ class MessagesViewModel(
|
||||||
val matrix = MatrixInstance.getInstance()
|
val matrix = MatrixInstance.getInstance()
|
||||||
val client = matrix.activeClient()
|
val client = matrix.activeClient()
|
||||||
val room = client.getRoom(state.roomId) ?: return null
|
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)
|
}.launchIn(viewModelScope)
|
||||||
|
|
||||||
timeline.timelineItems()
|
timeline.timelineItems()
|
||||||
.map { timelineItems ->
|
.map(messageTimelineItemStateMapper::map)
|
||||||
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
|
|
||||||
}
|
|
||||||
.execute {
|
.execute {
|
||||||
copy(timelineItems = it)
|
copy(timelineItems = it)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue