Timeline : remove the encrypted history banner for now.
This commit is contained in:
parent
fc0bb642f6
commit
74c02cc2d3
17 changed files with 3 additions and 306 deletions
|
|
@ -16,14 +16,12 @@ import androidx.compose.runtime.rememberUpdatedState
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import io.element.android.features.messages.impl.timeline.TimelineEvents
|
import io.element.android.features.messages.impl.timeline.TimelineEvents
|
||||||
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
||||||
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineEncryptedHistoryBannerView
|
|
||||||
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineItemDaySeparatorView
|
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineItemDaySeparatorView
|
||||||
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineItemReadMarkerView
|
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineItemReadMarkerView
|
||||||
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineItemRoomBeginningView
|
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineItemRoomBeginningView
|
||||||
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineLoadingMoreIndicator
|
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineLoadingMoreIndicator
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
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.TimelineItemEncryptedHistoryBannerVirtualModel
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemLastForwardIndicatorModel
|
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemLastForwardIndicatorModel
|
||||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemLoadingIndicatorModel
|
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemLoadingIndicatorModel
|
||||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemReadMarkerModel
|
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemReadMarkerModel
|
||||||
|
|
@ -40,7 +38,6 @@ fun TimelineItemVirtualRow(
|
||||||
when (virtual.model) {
|
when (virtual.model) {
|
||||||
is TimelineItemDaySeparatorModel -> TimelineItemDaySeparatorView(virtual.model)
|
is TimelineItemDaySeparatorModel -> TimelineItemDaySeparatorView(virtual.model)
|
||||||
TimelineItemReadMarkerModel -> TimelineItemReadMarkerView()
|
TimelineItemReadMarkerModel -> TimelineItemReadMarkerView()
|
||||||
is TimelineItemEncryptedHistoryBannerVirtualModel -> TimelineEncryptedHistoryBannerView()
|
|
||||||
TimelineItemRoomBeginningModel -> TimelineItemRoomBeginningView(roomName = timelineRoomInfo.name)
|
TimelineItemRoomBeginningModel -> TimelineItemRoomBeginningView(roomName = timelineRoomInfo.name)
|
||||||
is TimelineItemLoadingIndicatorModel -> {
|
is TimelineItemLoadingIndicatorModel -> {
|
||||||
TimelineLoadingMoreIndicator(virtual.model.direction)
|
TimelineLoadingMoreIndicator(virtual.model.direction)
|
||||||
|
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2023, 2024 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
* Please see LICENSE in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.element.android.features.messages.impl.timeline.components.virtual
|
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.border
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import io.element.android.compound.theme.ElementTheme
|
|
||||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
|
||||||
import io.element.android.features.messages.impl.R
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|
||||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun TimelineEncryptedHistoryBannerView(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = modifier
|
|
||||||
.padding(start = 16.dp, end = 16.dp, top = 24.dp, bottom = 32.dp)
|
|
||||||
.clip(MaterialTheme.shapes.small)
|
|
||||||
.border(1.dp, ElementTheme.colors.borderInfoSubtle, MaterialTheme.shapes.small)
|
|
||||||
.background(ElementTheme.colors.bgInfoSubtle)
|
|
||||||
.padding(16.dp),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
modifier = Modifier.size(20.dp),
|
|
||||||
imageVector = CompoundIcons.InfoSolid(),
|
|
||||||
contentDescription = null,
|
|
||||||
tint = ElementTheme.colors.iconInfoPrimary
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.screen_room_encrypted_history_banner),
|
|
||||||
style = ElementTheme.typography.fontBodyMdMedium,
|
|
||||||
color = ElementTheme.colors.textInfoPrimary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@PreviewsDayNight
|
|
||||||
@Composable
|
|
||||||
internal fun EncryptedHistoryBannerViewPreview() = ElementPreview {
|
|
||||||
TimelineEncryptedHistoryBannerView()
|
|
||||||
}
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
package io.element.android.features.messages.impl.timeline.factories.virtual
|
package io.element.android.features.messages.impl.timeline.factories.virtual
|
||||||
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemEncryptedHistoryBannerVirtualModel
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemLastForwardIndicatorModel
|
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemLastForwardIndicatorModel
|
||||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemLoadingIndicatorModel
|
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemLoadingIndicatorModel
|
||||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemReadMarkerModel
|
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemReadMarkerModel
|
||||||
|
|
@ -34,7 +33,6 @@ class TimelineItemVirtualFactory @Inject constructor(
|
||||||
return when (val inner = virtual) {
|
return when (val inner = virtual) {
|
||||||
is VirtualTimelineItem.DayDivider -> daySeparatorFactory.create(inner)
|
is VirtualTimelineItem.DayDivider -> daySeparatorFactory.create(inner)
|
||||||
is VirtualTimelineItem.ReadMarker -> TimelineItemReadMarkerModel
|
is VirtualTimelineItem.ReadMarker -> TimelineItemReadMarkerModel
|
||||||
is VirtualTimelineItem.EncryptedHistoryBanner -> TimelineItemEncryptedHistoryBannerVirtualModel
|
|
||||||
is VirtualTimelineItem.RoomBeginning -> TimelineItemRoomBeginningModel
|
is VirtualTimelineItem.RoomBeginning -> TimelineItemRoomBeginningModel
|
||||||
is VirtualTimelineItem.LoadingIndicator -> TimelineItemLoadingIndicatorModel(
|
is VirtualTimelineItem.LoadingIndicator -> TimelineItemLoadingIndicatorModel(
|
||||||
direction = inner.direction,
|
direction = inner.direction,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2023, 2024 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
* Please see LICENSE in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.element.android.features.messages.impl.timeline.model.virtual
|
|
||||||
|
|
||||||
data object TimelineItemEncryptedHistoryBannerVirtualModel : TimelineItemVirtualModel {
|
|
||||||
override val type: String = "TimelineItemEncryptedHistoryBannerVirtualModel"
|
|
||||||
}
|
|
||||||
|
|
@ -16,8 +16,6 @@ sealed interface VirtualTimelineItem {
|
||||||
|
|
||||||
data object ReadMarker : VirtualTimelineItem
|
data object ReadMarker : VirtualTimelineItem
|
||||||
|
|
||||||
data object EncryptedHistoryBanner : VirtualTimelineItem
|
|
||||||
|
|
||||||
data object RoomBeginning : VirtualTimelineItem
|
data object RoomBeginning : VirtualTimelineItem
|
||||||
|
|
||||||
data object LastForwardIndicator : VirtualTimelineItem
|
data object LastForwardIndicator : VirtualTimelineItem
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,6 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.coroutines.withTimeout
|
import kotlinx.coroutines.withTimeout
|
||||||
import org.matrix.rustcomponents.sdk.BackupState
|
|
||||||
import org.matrix.rustcomponents.sdk.Client
|
import org.matrix.rustcomponents.sdk.Client
|
||||||
import org.matrix.rustcomponents.sdk.ClientException
|
import org.matrix.rustcomponents.sdk.ClientException
|
||||||
import org.matrix.rustcomponents.sdk.IgnoredUsersListener
|
import org.matrix.rustcomponents.sdk.IgnoredUsersListener
|
||||||
|
|
@ -179,7 +178,6 @@ class RustMatrixClient(
|
||||||
systemClock = clock,
|
systemClock = clock,
|
||||||
roomContentForwarder = RoomContentForwarder(innerRoomListService),
|
roomContentForwarder = RoomContentForwarder(innerRoomListService),
|
||||||
roomSyncSubscriber = roomSyncSubscriber,
|
roomSyncSubscriber = roomSyncSubscriber,
|
||||||
isKeyBackupEnabled = { client.encryption().use { it.backupState() == BackupState.ENABLED } },
|
|
||||||
getSessionData = { sessionStore.getSession(sessionId.value)!! },
|
getSessionData = { sessionStore.getSession(sessionId.value)!! },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,6 @@ import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class RustMatrixRoom(
|
class RustMatrixRoom(
|
||||||
override val sessionId: SessionId,
|
override val sessionId: SessionId,
|
||||||
private val isKeyBackupEnabled: Boolean,
|
|
||||||
private val roomListItem: RoomListItem,
|
private val roomListItem: RoomListItem,
|
||||||
private val innerRoom: InnerRoom,
|
private val innerRoom: InnerRoom,
|
||||||
innerTimeline: InnerTimeline,
|
innerTimeline: InnerTimeline,
|
||||||
|
|
@ -652,16 +651,14 @@ class RustMatrixRoom(
|
||||||
): Timeline {
|
): Timeline {
|
||||||
val timelineCoroutineScope = roomCoroutineScope.childScope(coroutineDispatchers.main, "TimelineScope-$roomId-$timeline")
|
val timelineCoroutineScope = roomCoroutineScope.childScope(coroutineDispatchers.main, "TimelineScope-$roomId-$timeline")
|
||||||
return RustTimeline(
|
return RustTimeline(
|
||||||
isKeyBackupEnabled = isKeyBackupEnabled,
|
|
||||||
mode = mode,
|
mode = mode,
|
||||||
matrixRoom = this,
|
matrixRoom = this,
|
||||||
|
inner = timeline,
|
||||||
systemClock = systemClock,
|
systemClock = systemClock,
|
||||||
coroutineScope = timelineCoroutineScope,
|
coroutineScope = timelineCoroutineScope,
|
||||||
dispatcher = roomDispatcher,
|
dispatcher = roomDispatcher,
|
||||||
lastLoginTimestamp = sessionData.loginTimestamp,
|
|
||||||
onNewSyncedEvent = onNewSyncedEvent,
|
|
||||||
roomContentForwarder = roomContentForwarder,
|
roomContentForwarder = roomContentForwarder,
|
||||||
inner = timeline,
|
onNewSyncedEvent = onNewSyncedEvent,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ class RustRoomFactory(
|
||||||
private val roomListService: RoomListService,
|
private val roomListService: RoomListService,
|
||||||
private val innerRoomListService: InnerRoomListService,
|
private val innerRoomListService: InnerRoomListService,
|
||||||
private val roomSyncSubscriber: RoomSyncSubscriber,
|
private val roomSyncSubscriber: RoomSyncSubscriber,
|
||||||
private val isKeyBackupEnabled: suspend () -> Boolean,
|
|
||||||
private val getSessionData: suspend () -> SessionData,
|
private val getSessionData: suspend () -> SessionData,
|
||||||
) {
|
) {
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
|
@ -109,7 +108,6 @@ class RustRoomFactory(
|
||||||
val liveTimeline = roomReferences.fullRoom.timeline()
|
val liveTimeline = roomReferences.fullRoom.timeline()
|
||||||
RustMatrixRoom(
|
RustMatrixRoom(
|
||||||
sessionId = sessionId,
|
sessionId = sessionId,
|
||||||
isKeyBackupEnabled = isKeyBackupEnabled(),
|
|
||||||
roomListItem = roomReferences.roomListItem,
|
roomListItem = roomReferences.roomListItem,
|
||||||
innerRoom = roomReferences.fullRoom,
|
innerRoom = roomReferences.fullRoom,
|
||||||
innerTimeline = liveTimeline,
|
innerTimeline = liveTimeline,
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,6 @@ import io.element.android.libraries.matrix.impl.timeline.item.virtual.VirtualTim
|
||||||
import io.element.android.libraries.matrix.impl.timeline.postprocessor.LastForwardIndicatorsPostProcessor
|
import io.element.android.libraries.matrix.impl.timeline.postprocessor.LastForwardIndicatorsPostProcessor
|
||||||
import io.element.android.libraries.matrix.impl.timeline.postprocessor.LoadingIndicatorsPostProcessor
|
import io.element.android.libraries.matrix.impl.timeline.postprocessor.LoadingIndicatorsPostProcessor
|
||||||
import io.element.android.libraries.matrix.impl.timeline.postprocessor.RoomBeginningPostProcessor
|
import io.element.android.libraries.matrix.impl.timeline.postprocessor.RoomBeginningPostProcessor
|
||||||
import io.element.android.libraries.matrix.impl.timeline.postprocessor.TimelineEncryptedHistoryPostProcessor
|
|
||||||
import io.element.android.libraries.matrix.impl.timeline.reply.InReplyToMapper
|
import io.element.android.libraries.matrix.impl.timeline.reply.InReplyToMapper
|
||||||
import io.element.android.libraries.matrix.impl.util.MessageEventContent
|
import io.element.android.libraries.matrix.impl.util.MessageEventContent
|
||||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||||
|
|
@ -70,7 +69,6 @@ import org.matrix.rustcomponents.sdk.use
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uniffi.matrix_sdk_ui.LiveBackPaginationStatus
|
import uniffi.matrix_sdk_ui.LiveBackPaginationStatus
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Date
|
|
||||||
import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline
|
import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline
|
||||||
|
|
||||||
private const val PAGINATION_SIZE = 50
|
private const val PAGINATION_SIZE = 50
|
||||||
|
|
@ -79,11 +77,9 @@ class RustTimeline(
|
||||||
private val inner: InnerTimeline,
|
private val inner: InnerTimeline,
|
||||||
mode: Timeline.Mode,
|
mode: Timeline.Mode,
|
||||||
systemClock: SystemClock,
|
systemClock: SystemClock,
|
||||||
isKeyBackupEnabled: Boolean,
|
|
||||||
private val matrixRoom: MatrixRoom,
|
private val matrixRoom: MatrixRoom,
|
||||||
private val coroutineScope: CoroutineScope,
|
private val coroutineScope: CoroutineScope,
|
||||||
private val dispatcher: CoroutineDispatcher,
|
private val dispatcher: CoroutineDispatcher,
|
||||||
lastLoginTimestamp: Date?,
|
|
||||||
private val roomContentForwarder: RoomContentForwarder,
|
private val roomContentForwarder: RoomContentForwarder,
|
||||||
onNewSyncedEvent: () -> Unit,
|
onNewSyncedEvent: () -> Unit,
|
||||||
) : Timeline {
|
) : Timeline {
|
||||||
|
|
@ -107,12 +103,6 @@ class RustTimeline(
|
||||||
timelineItems = _timelineItems,
|
timelineItems = _timelineItems,
|
||||||
timelineItemFactory = timelineItemMapper,
|
timelineItemFactory = timelineItemMapper,
|
||||||
)
|
)
|
||||||
private val encryptedHistoryPostProcessor = TimelineEncryptedHistoryPostProcessor(
|
|
||||||
lastLoginTimestamp = lastLoginTimestamp,
|
|
||||||
isRoomEncrypted = matrixRoom.isEncrypted,
|
|
||||||
isKeyBackupEnabled = isKeyBackupEnabled,
|
|
||||||
dispatcher = dispatcher,
|
|
||||||
)
|
|
||||||
private val timelineItemsSubscriber = TimelineItemsSubscriber(
|
private val timelineItemsSubscriber = TimelineItemsSubscriber(
|
||||||
timeline = inner,
|
timeline = inner,
|
||||||
timelineCoroutineScope = coroutineScope,
|
timelineCoroutineScope = coroutineScope,
|
||||||
|
|
@ -219,7 +209,6 @@ class RustTimeline(
|
||||||
) { timelineItems, hasMoreToLoadBackward, hasMoreToLoadForward, isInit ->
|
) { timelineItems, hasMoreToLoadBackward, hasMoreToLoadForward, isInit ->
|
||||||
withContext(dispatcher) {
|
withContext(dispatcher) {
|
||||||
timelineItems
|
timelineItems
|
||||||
.process { items -> encryptedHistoryPostProcessor.process(items) }
|
|
||||||
.process { items ->
|
.process { items ->
|
||||||
roomBeginningPostProcessor.process(
|
roomBeginningPostProcessor.process(
|
||||||
items = items,
|
items = items,
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2024 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
* Please see LICENSE in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.impl.timeline.postprocessor
|
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
|
|
||||||
|
|
||||||
internal fun List<MatrixTimelineItem>.hasEncryptionHistoryBanner(): Boolean {
|
|
||||||
val firstItem = firstOrNull()
|
|
||||||
return firstItem is MatrixTimelineItem.Virtual &&
|
|
||||||
firstItem.virtual is VirtualTimelineItem.EncryptedHistoryBanner
|
|
||||||
}
|
|
||||||
|
|
@ -19,11 +19,10 @@ class LoadingIndicatorsPostProcessor(private val systemClock: SystemClock) {
|
||||||
hasMoreToLoadBackward: Boolean,
|
hasMoreToLoadBackward: Boolean,
|
||||||
hasMoreToLoadForward: Boolean,
|
hasMoreToLoadForward: Boolean,
|
||||||
): List<MatrixTimelineItem> {
|
): List<MatrixTimelineItem> {
|
||||||
val shouldAddBackwardLoadingIndicator = hasMoreToLoadBackward && !items.hasEncryptionHistoryBanner()
|
|
||||||
val shouldAddForwardLoadingIndicator = hasMoreToLoadForward && items.isNotEmpty()
|
val shouldAddForwardLoadingIndicator = hasMoreToLoadForward && items.isNotEmpty()
|
||||||
val currentTimestamp = systemClock.epochMillis()
|
val currentTimestamp = systemClock.epochMillis()
|
||||||
return buildList {
|
return buildList {
|
||||||
if (shouldAddBackwardLoadingIndicator) {
|
if (hasMoreToLoadBackward) {
|
||||||
val backwardLoadingIndicator = MatrixTimelineItem.Virtual(
|
val backwardLoadingIndicator = MatrixTimelineItem.Virtual(
|
||||||
uniqueId = UniqueId("BackwardLoadingIndicator"),
|
uniqueId = UniqueId("BackwardLoadingIndicator"),
|
||||||
virtual = VirtualTimelineItem.LoadingIndicator(
|
virtual = VirtualTimelineItem.LoadingIndicator(
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@ class RoomBeginningPostProcessor(private val mode: Timeline.Mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processForRoom(items: List<MatrixTimelineItem>): List<MatrixTimelineItem> {
|
private fun processForRoom(items: List<MatrixTimelineItem>): List<MatrixTimelineItem> {
|
||||||
if (items.hasEncryptionHistoryBanner()) return items
|
|
||||||
val roomBeginningItem = createRoomBeginningItem()
|
val roomBeginningItem = createRoomBeginningItem()
|
||||||
return listOf(roomBeginningItem) + items
|
return listOf(roomBeginningItem) + items
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2023, 2024 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
* Please see LICENSE in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.impl.timeline.postprocessor
|
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.core.UniqueId
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
|
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.util.Date
|
|
||||||
|
|
||||||
internal val encryptedHistoryBannerId = UniqueId("EncryptedHistoryBannerId")
|
|
||||||
|
|
||||||
class TimelineEncryptedHistoryPostProcessor(
|
|
||||||
private val dispatcher: CoroutineDispatcher,
|
|
||||||
private val lastLoginTimestamp: Date?,
|
|
||||||
private val isRoomEncrypted: Boolean,
|
|
||||||
private val isKeyBackupEnabled: Boolean,
|
|
||||||
) {
|
|
||||||
suspend fun process(items: List<MatrixTimelineItem>): List<MatrixTimelineItem> = withContext(dispatcher) {
|
|
||||||
Timber.d("Process on Thread=${Thread.currentThread()}")
|
|
||||||
if (!isRoomEncrypted || isKeyBackupEnabled || lastLoginTimestamp == null) return@withContext items
|
|
||||||
replaceWithEncryptionHistoryBannerIfNeeded(items)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun replaceWithEncryptionHistoryBannerIfNeeded(list: List<MatrixTimelineItem>): List<MatrixTimelineItem> {
|
|
||||||
var lastEncryptedHistoryBannerIndex = -1
|
|
||||||
for ((i, item) in list.withIndex()) {
|
|
||||||
if (isItemEncryptionHistory(item)) {
|
|
||||||
lastEncryptedHistoryBannerIndex = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return if (lastEncryptedHistoryBannerIndex >= 0) {
|
|
||||||
val sublist = list.drop(lastEncryptedHistoryBannerIndex + 1).toMutableList()
|
|
||||||
sublist.add(0, MatrixTimelineItem.Virtual(encryptedHistoryBannerId, VirtualTimelineItem.EncryptedHistoryBanner))
|
|
||||||
sublist
|
|
||||||
} else {
|
|
||||||
list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isItemEncryptionHistory(item: MatrixTimelineItem): Boolean {
|
|
||||||
if ((item as? MatrixTimelineItem.Virtual)?.virtual is VirtualTimelineItem.EncryptedHistoryBanner) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
val timestamp = (item as? MatrixTimelineItem.Event)?.event?.timestamp ?: return false
|
|
||||||
return timestamp <= lastLoginTimestamp!!.time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -15,7 +15,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.MembershipCha
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
|
import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
|
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
||||||
import io.element.android.libraries.matrix.test.timeline.aMessageContent
|
import io.element.android.libraries.matrix.test.timeline.aMessageContent
|
||||||
|
|
@ -70,16 +69,6 @@ class RoomBeginningPostProcessorTest {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `processor will not add beginning of room item if it's not a DM and EncryptedHistoryBanner item is found`() {
|
|
||||||
val timelineItems = listOf(
|
|
||||||
MatrixTimelineItem.Virtual(UniqueId("EncryptedHistoryBanner"), VirtualTimelineItem.EncryptedHistoryBanner),
|
|
||||||
)
|
|
||||||
val processor = RoomBeginningPostProcessor(Timeline.Mode.LIVE)
|
|
||||||
val processedItems = processor.process(timelineItems, isDm = false, hasMoreToLoadBackwards = false)
|
|
||||||
assertThat(processedItems).isEqualTo(timelineItems)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `processor won't remove items if it's not at the start of the timeline`() {
|
fun `processor won't remove items if it's not at the start of the timeline`() {
|
||||||
val timelineItems = listOf(
|
val timelineItems = listOf(
|
||||||
|
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2023, 2024 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
* Please see LICENSE in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.impl.timeline.postprocessor
|
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
|
|
||||||
import io.element.android.libraries.matrix.test.A_UNIQUE_ID
|
|
||||||
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
|
||||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
|
||||||
import kotlinx.coroutines.test.TestScope
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import org.junit.Test
|
|
||||||
import java.util.Date
|
|
||||||
|
|
||||||
class TimelineEncryptedHistoryPostProcessorTest {
|
|
||||||
private val defaultLastLoginTimestamp = Date(1_689_061_264L)
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `given an unencrypted room, nothing is done`() = runTest {
|
|
||||||
val processor = createPostProcessor(isRoomEncrypted = false)
|
|
||||||
val items = listOf(
|
|
||||||
MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem())
|
|
||||||
)
|
|
||||||
assertThat(processor.process(items)).isSameInstanceAs(items)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `given an encrypted room, and key backup enabled, nothing is done`() = runTest {
|
|
||||||
val processor = createPostProcessor(isKeyBackupEnabled = true)
|
|
||||||
val items = listOf(
|
|
||||||
MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem())
|
|
||||||
)
|
|
||||||
assertThat(processor.process(items)).isSameInstanceAs(items)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `given a null lastLoginTimestamp, nothing is done`() = runTest {
|
|
||||||
val processor = createPostProcessor(lastLoginTimestamp = null)
|
|
||||||
val items = listOf(
|
|
||||||
MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem())
|
|
||||||
)
|
|
||||||
assertThat(processor.process(items)).isSameInstanceAs(items)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `given an empty list, nothing is done`() = runTest {
|
|
||||||
val processor = createPostProcessor()
|
|
||||||
val items = emptyList<MatrixTimelineItem>()
|
|
||||||
assertThat(processor.process(items)).isSameInstanceAs(items)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `given a list with no items before lastLoginTimestamp, nothing is done`() = runTest {
|
|
||||||
val processor = createPostProcessor()
|
|
||||||
val items = listOf(
|
|
||||||
MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem(timestamp = defaultLastLoginTimestamp.time + 1))
|
|
||||||
)
|
|
||||||
assertThat(processor.process(items)).isSameInstanceAs(items)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `given a list with an item with equal timestamp as lastLoginTimestamp, it's replaced`() = runTest {
|
|
||||||
val processor = createPostProcessor()
|
|
||||||
val items = listOf(
|
|
||||||
MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem(timestamp = defaultLastLoginTimestamp.time))
|
|
||||||
)
|
|
||||||
assertThat(processor.process(items))
|
|
||||||
.isEqualTo(listOf(MatrixTimelineItem.Virtual(encryptedHistoryBannerId, VirtualTimelineItem.EncryptedHistoryBanner)))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `given a list with an item with a lower timestamp than lastLoginTimestamp, it's replaced`() = runTest {
|
|
||||||
val processor = createPostProcessor()
|
|
||||||
val items = listOf(
|
|
||||||
MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem(timestamp = defaultLastLoginTimestamp.time - 1))
|
|
||||||
)
|
|
||||||
assertThat(processor.process(items)).isEqualTo(
|
|
||||||
listOf(MatrixTimelineItem.Virtual(encryptedHistoryBannerId, VirtualTimelineItem.EncryptedHistoryBanner))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `given a list with several with lower or equal timestamps than lastLoginTimestamp, then they're replaced`() = runTest {
|
|
||||||
val processor = createPostProcessor()
|
|
||||||
val items = listOf(
|
|
||||||
MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem(timestamp = defaultLastLoginTimestamp.time - 1)),
|
|
||||||
MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem(timestamp = defaultLastLoginTimestamp.time)),
|
|
||||||
MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem(timestamp = defaultLastLoginTimestamp.time + 1)),
|
|
||||||
)
|
|
||||||
assertThat(processor.process(items)).isEqualTo(
|
|
||||||
listOf(
|
|
||||||
MatrixTimelineItem.Virtual(encryptedHistoryBannerId, VirtualTimelineItem.EncryptedHistoryBanner),
|
|
||||||
MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem(timestamp = defaultLastLoginTimestamp.time + 1))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun TestScope.createPostProcessor(
|
|
||||||
lastLoginTimestamp: Date? = defaultLastLoginTimestamp,
|
|
||||||
isRoomEncrypted: Boolean = true,
|
|
||||||
isKeyBackupEnabled: Boolean = false,
|
|
||||||
) = TimelineEncryptedHistoryPostProcessor(
|
|
||||||
lastLoginTimestamp = lastLoginTimestamp,
|
|
||||||
isRoomEncrypted = isRoomEncrypted,
|
|
||||||
isKeyBackupEnabled = isKeyBackupEnabled,
|
|
||||||
dispatcher = StandardTestDispatcher(testScheduler)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:47c6681e3cf56d3229953b7c34b6f1d531c492d23f4dffe77e2a12fbdbf44261
|
|
||||||
size 11892
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:985b87b568e34b16d132a5cde5781e99edc81be4ef53c5b6e67ca75472266f99
|
|
||||||
size 11436
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue