diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateMapper.kt b/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateMapper.kt new file mode 100644 index 0000000000..de088ea8dc --- /dev/null +++ b/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateMapper.kt @@ -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): List = + withContext(dispatcher) { + val messagesTimelineItemState = ArrayList() + 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 + } + + +} \ No newline at end of file diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt b/features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt index 3229265fb0..7c4fd23d43 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt @@ -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(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() - 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) }