ganfra
2 years ago
13 changed files with 293 additions and 161 deletions
@ -0,0 +1,62 @@
@@ -0,0 +1,62 @@
|
||||
/* |
||||
* Copyright (c) 2023 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.timeline.components.event |
||||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource |
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.ui.Modifier |
||||
import io.element.android.features.messages.timeline.model.event.TimelineItemEncryptedContent |
||||
import io.element.android.features.messages.timeline.model.event.TimelineItemEventContent |
||||
import io.element.android.features.messages.timeline.model.event.TimelineItemImageContent |
||||
import io.element.android.features.messages.timeline.model.event.TimelineItemRedactedContent |
||||
import io.element.android.features.messages.timeline.model.event.TimelineItemTextBasedContent |
||||
import io.element.android.features.messages.timeline.model.event.TimelineItemUnknownContent |
||||
|
||||
@Composable |
||||
fun TimelineItemEventContentView( |
||||
content: TimelineItemEventContent, |
||||
interactionSource: MutableInteractionSource, |
||||
onClick: () -> Unit, |
||||
onLongClick: () -> Unit, |
||||
modifier: Modifier = Modifier |
||||
) { |
||||
when (content) { |
||||
is TimelineItemEncryptedContent -> TimelineItemEncryptedView( |
||||
content = content, |
||||
modifier = modifier |
||||
) |
||||
is TimelineItemRedactedContent -> TimelineItemRedactedView( |
||||
content = content, |
||||
modifier = modifier |
||||
) |
||||
is TimelineItemTextBasedContent -> TimelineItemTextView( |
||||
content = content, |
||||
interactionSource = interactionSource, |
||||
modifier = modifier, |
||||
onTextClicked = onClick, |
||||
onTextLongClicked = onLongClick |
||||
) |
||||
is TimelineItemUnknownContent -> TimelineItemUnknownView( |
||||
content = content, |
||||
modifier = modifier |
||||
) |
||||
is TimelineItemImageContent -> TimelineItemImageView( |
||||
content = content, |
||||
modifier = modifier |
||||
) |
||||
} |
||||
} |
@ -0,0 +1,118 @@
@@ -0,0 +1,118 @@
|
||||
/* |
||||
* Copyright (c) 2023 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.libraries.matrix.timeline |
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher |
||||
import kotlinx.coroutines.CoroutineScope |
||||
import kotlinx.coroutines.flow.MutableStateFlow |
||||
import kotlinx.coroutines.launch |
||||
import kotlinx.coroutines.withContext |
||||
import org.matrix.rustcomponents.sdk.TimelineChange |
||||
import org.matrix.rustcomponents.sdk.TimelineDiff |
||||
import org.matrix.rustcomponents.sdk.TimelineListener |
||||
import org.matrix.rustcomponents.sdk.VirtualTimelineItem |
||||
|
||||
internal class MatrixTimelineDiffProcessor( |
||||
private val paginationState: MutableStateFlow<MatrixTimeline.PaginationState>, |
||||
private val timelineItems: MutableStateFlow<List<MatrixTimelineItem>>, |
||||
private val coroutineScope: CoroutineScope, |
||||
private val diffDispatcher: CoroutineDispatcher, |
||||
) : TimelineListener { |
||||
|
||||
override fun onUpdate(update: TimelineDiff) { |
||||
coroutineScope.launch { |
||||
updateTimelineItems { |
||||
applyDiff(update) |
||||
} |
||||
when (val firstItem = timelineItems.value.firstOrNull()) { |
||||
is MatrixTimelineItem.Virtual -> updateBackPaginationState(firstItem.virtual) |
||||
else -> updateBackPaginationState(null) |
||||
} |
||||
} |
||||
} |
||||
|
||||
private fun updateBackPaginationState(virtualItem: VirtualTimelineItem?) { |
||||
val currentPaginationState = paginationState.value |
||||
val newPaginationState = when (virtualItem) { |
||||
VirtualTimelineItem.LoadingIndicator -> currentPaginationState.copy( |
||||
isBackPaginating = true, |
||||
canBackPaginate = true |
||||
) |
||||
VirtualTimelineItem.TimelineStart -> currentPaginationState.copy( |
||||
isBackPaginating = false, |
||||
canBackPaginate = false |
||||
) |
||||
else -> currentPaginationState.copy( |
||||
isBackPaginating = false, |
||||
canBackPaginate = true |
||||
) |
||||
} |
||||
paginationState.value = newPaginationState |
||||
} |
||||
|
||||
private suspend fun updateTimelineItems(block: MutableList<MatrixTimelineItem>.() -> Unit) = |
||||
withContext(diffDispatcher) { |
||||
val mutableTimelineItems = timelineItems.value.toMutableList() |
||||
block(mutableTimelineItems) |
||||
timelineItems.value = mutableTimelineItems |
||||
} |
||||
|
||||
private fun MutableList<MatrixTimelineItem>.applyDiff(diff: TimelineDiff) { |
||||
when (diff.change()) { |
||||
TimelineChange.APPEND -> { |
||||
val items = diff.append()?.map { it.asMatrixTimelineItem() } ?: return |
||||
addAll(items) |
||||
} |
||||
TimelineChange.PUSH_BACK -> { |
||||
val item = diff.pushBack()?.asMatrixTimelineItem() ?: return |
||||
add(item) |
||||
} |
||||
TimelineChange.PUSH_FRONT -> { |
||||
val item = diff.pushFront()?.asMatrixTimelineItem() ?: return |
||||
add(0, item) |
||||
} |
||||
TimelineChange.SET -> { |
||||
val updateAtData = diff.set() ?: return |
||||
val item = updateAtData.item.asMatrixTimelineItem() |
||||
set(updateAtData.index.toInt(), item) |
||||
} |
||||
TimelineChange.INSERT -> { |
||||
val insertAtData = diff.insert() ?: return |
||||
val item = insertAtData.item.asMatrixTimelineItem() |
||||
add(insertAtData.index.toInt(), item) |
||||
} |
||||
TimelineChange.REMOVE -> { |
||||
val removeAtData = diff.remove() ?: return |
||||
removeAt(removeAtData.toInt()) |
||||
} |
||||
TimelineChange.RESET -> { |
||||
clear() |
||||
val items = diff.reset()?.map { it.asMatrixTimelineItem() } ?: return |
||||
addAll(items) |
||||
} |
||||
TimelineChange.POP_FRONT -> { |
||||
removeFirstOrNull() |
||||
} |
||||
TimelineChange.POP_BACK -> { |
||||
removeLastOrNull() |
||||
} |
||||
TimelineChange.CLEAR -> { |
||||
clear() |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue