Browse Source

Timeline : add a mode to differentiate between live/focused/pinned

pull/3392/head
ganfra 2 months ago
parent
commit
741c3679ea
  1. 6
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt
  2. 10
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt
  3. 12
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt
  4. 7
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/LastForwardIndicatorsPostProcessor.kt
  5. 4
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/RoomBeginningPostProcessor.kt
  6. 14
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/RoomBeginningPostProcessorTest.kt

6
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt

@ -46,6 +46,12 @@ interface Timeline : AutoCloseable { @@ -46,6 +46,12 @@ interface Timeline : AutoCloseable {
FORWARDS
}
enum class Mode {
LIVE,
FOCUSED_ON_EVENT,
FOCUSED_ON_PINNED_EVENTS
}
val membershipChangeEventReceived: Flow<Unit>
suspend fun sendReadReceipt(eventId: EventId, receiptType: ReceiptType): Result<Unit>
suspend fun paginate(direction: PaginationDirection): Result<Boolean>

10
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt

@ -153,7 +153,7 @@ class RustMatrixRoom( @@ -153,7 +153,7 @@ class RustMatrixRoom(
private val _roomNotificationSettingsStateFlow = MutableStateFlow<MatrixRoomNotificationSettingsState>(MatrixRoomNotificationSettingsState.Unknown)
override val roomNotificationSettingsStateFlow: StateFlow<MatrixRoomNotificationSettingsState> = _roomNotificationSettingsStateFlow
override val liveTimeline = createTimeline(innerTimeline, isLive = true) {
override val liveTimeline = createTimeline(innerTimeline, mode = Timeline.Mode.LIVE) {
_syncUpdateFlow.value = systemClock.epochMillis()
}
@ -181,7 +181,7 @@ class RustMatrixRoom( @@ -181,7 +181,7 @@ class RustMatrixRoom(
numContextEvents = 50u,
internalIdPrefix = "focus_$eventId",
).let { inner ->
createTimeline(inner, isLive = false)
createTimeline(inner, mode = Timeline.Mode.FOCUSED_ON_EVENT)
}
}.mapFailure {
it.toFocusEventException()
@ -198,7 +198,7 @@ class RustMatrixRoom( @@ -198,7 +198,7 @@ class RustMatrixRoom(
internalIdPrefix = "pinned_events",
maxEventsToLoad = 100u,
).let { inner ->
createTimeline(inner, isLive = false)
createTimeline(inner, mode = Timeline.Mode.FOCUSED_ON_PINNED_EVENTS)
}
}.onFailure {
if (it is CancellationException) {
@ -655,13 +655,13 @@ class RustMatrixRoom( @@ -655,13 +655,13 @@ class RustMatrixRoom(
private fun createTimeline(
timeline: InnerTimeline,
isLive: Boolean,
mode: Timeline.Mode,
onNewSyncedEvent: () -> Unit = {},
): Timeline {
val timelineCoroutineScope = roomCoroutineScope.childScope(coroutineDispatchers.main, "TimelineScope-$roomId-$timeline")
return RustTimeline(
isKeyBackupEnabled = isKeyBackupEnabled,
isLive = isLive,
mode = mode,
matrixRoom = this,
systemClock = systemClock,
coroutineScope = timelineCoroutineScope,

12
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt

@ -85,7 +85,7 @@ private const val PAGINATION_SIZE = 50 @@ -85,7 +85,7 @@ private const val PAGINATION_SIZE = 50
class RustTimeline(
private val inner: InnerTimeline,
private val isLive: Boolean,
mode: Timeline.Mode,
systemClock: SystemClock,
isKeyBackupEnabled: Boolean,
private val matrixRoom: MatrixRoom,
@ -131,21 +131,21 @@ class RustTimeline( @@ -131,21 +131,21 @@ class RustTimeline(
onNewSyncedEvent = onNewSyncedEvent,
)
private val roomBeginningPostProcessor = RoomBeginningPostProcessor()
private val roomBeginningPostProcessor = RoomBeginningPostProcessor(mode)
private val loadingIndicatorsPostProcessor = LoadingIndicatorsPostProcessor(systemClock)
private val lastForwardIndicatorsPostProcessor = LastForwardIndicatorsPostProcessor(isLive)
private val lastForwardIndicatorsPostProcessor = LastForwardIndicatorsPostProcessor(mode)
private val backPaginationStatus = MutableStateFlow(
Timeline.PaginationStatus(isPaginating = false, hasMoreToLoad = true)
Timeline.PaginationStatus(isPaginating = false, hasMoreToLoad = mode != Timeline.Mode.FOCUSED_ON_PINNED_EVENTS)
)
private val forwardPaginationStatus = MutableStateFlow(
Timeline.PaginationStatus(isPaginating = false, hasMoreToLoad = !isLive)
Timeline.PaginationStatus(isPaginating = false, hasMoreToLoad = mode == Timeline.Mode.FOCUSED_ON_EVENT)
)
init {
coroutineScope.fetchMembers()
if (isLive) {
if (mode == Timeline.Mode.LIVE) {
// When timeline is live, we need to listen to the back pagination status as
// sdk can automatically paginate backwards.
coroutineScope.registerBackPaginationStatusListener()

7
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/LastForwardIndicatorsPostProcessor.kt

@ -17,21 +17,22 @@ @@ -17,21 +17,22 @@
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.Timeline
import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
/**
* This post processor is responsible for adding virtual items to indicate all the previous last forward item.
*/
class LastForwardIndicatorsPostProcessor(
private val isTimelineLive: Boolean,
private val mode: Timeline.Mode,
) {
private val lastForwardIdentifiers = LinkedHashSet<String>()
fun process(
items: List<MatrixTimelineItem>,
): List<MatrixTimelineItem> {
// If the timeline is live, we don't have any last forward indicator to display
if (isTimelineLive) {
// We don't need to add the last forward indicator if we are not in the FOCUSED_ON_EVENT mode
if (mode != Timeline.Mode.FOCUSED_ON_EVENT) {
return items
} else {
return buildList {

4
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/RoomBeginningPostProcessor.kt

@ -18,6 +18,7 @@ package io.element.android.libraries.matrix.impl.timeline.postprocessor @@ -18,6 +18,7 @@ package io.element.android.libraries.matrix.impl.timeline.postprocessor
import androidx.annotation.VisibleForTesting
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.Timeline
import io.element.android.libraries.matrix.api.timeline.item.event.MembershipChange
import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
@ -28,13 +29,14 @@ import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTime @@ -28,13 +29,14 @@ import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTime
* This timeline post-processor removes the room creation event and the self-join event from the timeline for DMs
* or add the RoomBeginning item for non DM room.
*/
class RoomBeginningPostProcessor {
class RoomBeginningPostProcessor(private val mode: Timeline.Mode) {
fun process(
items: List<MatrixTimelineItem>,
isDm: Boolean,
hasMoreToLoadBackwards: Boolean
): List<MatrixTimelineItem> {
return when {
mode == Timeline.Mode.FOCUSED_ON_PINNED_EVENTS -> items
hasMoreToLoadBackwards -> items
isDm -> processForDM(items)
else -> processForRoom(items)

14
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/RoomBeginningPostProcessorTest.kt

@ -36,7 +36,7 @@ class RoomBeginningPostProcessorTest { @@ -36,7 +36,7 @@ class RoomBeginningPostProcessorTest {
MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))),
MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED))),
)
val processor = RoomBeginningPostProcessor()
val processor = RoomBeginningPostProcessor(mode)
val processedItems = processor.process(timelineItems, isDm = true, hasMoreToLoadBackwards = false)
assertThat(processedItems).isEmpty()
}
@ -53,7 +53,7 @@ class RoomBeginningPostProcessorTest { @@ -53,7 +53,7 @@ class RoomBeginningPostProcessorTest {
MatrixTimelineItem.Event("m.room.member_other", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID_2, null, MembershipChange.JOINED))),
MatrixTimelineItem.Event("m.room.message", anEventTimelineItem(content = aMessageContent("hi"))),
)
val processor = RoomBeginningPostProcessor()
val processor = RoomBeginningPostProcessor(mode)
val processedItems = processor.process(timelineItems, isDm = true, hasMoreToLoadBackwards = false)
assertThat(processedItems).isEqualTo(expected)
}
@ -64,7 +64,7 @@ class RoomBeginningPostProcessorTest { @@ -64,7 +64,7 @@ class RoomBeginningPostProcessorTest {
MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))),
MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED))),
)
val processor = RoomBeginningPostProcessor()
val processor = RoomBeginningPostProcessor(mode)
val processedItems = processor.process(timelineItems, isDm = false, hasMoreToLoadBackwards = false)
assertThat(processedItems).isEqualTo(
listOf(processor.createRoomBeginningItem()) + timelineItems
@ -76,7 +76,7 @@ class RoomBeginningPostProcessorTest { @@ -76,7 +76,7 @@ class RoomBeginningPostProcessorTest {
val timelineItems = listOf(
MatrixTimelineItem.Virtual("EncryptedHistoryBanner", VirtualTimelineItem.EncryptedHistoryBanner),
)
val processor = RoomBeginningPostProcessor()
val processor = RoomBeginningPostProcessor(mode)
val processedItems = processor.process(timelineItems, isDm = false, hasMoreToLoadBackwards = false)
assertThat(processedItems).isEqualTo(timelineItems)
}
@ -87,7 +87,7 @@ class RoomBeginningPostProcessorTest { @@ -87,7 +87,7 @@ class RoomBeginningPostProcessorTest {
MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))),
MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED))),
)
val processor = RoomBeginningPostProcessor()
val processor = RoomBeginningPostProcessor(mode)
val processedItems = processor.process(timelineItems, isDm = true, hasMoreToLoadBackwards = true)
assertThat(processedItems).isEqualTo(timelineItems)
}
@ -97,7 +97,7 @@ class RoomBeginningPostProcessorTest { @@ -97,7 +97,7 @@ class RoomBeginningPostProcessorTest {
val timelineItems = listOf(
MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED))),
)
val processor = RoomBeginningPostProcessor()
val processor = RoomBeginningPostProcessor(mode)
val processedItems = processor.process(timelineItems, isDm = true, hasMoreToLoadBackwards = true)
assertThat(processedItems).isEqualTo(timelineItems)
}
@ -108,7 +108,7 @@ class RoomBeginningPostProcessorTest { @@ -108,7 +108,7 @@ class RoomBeginningPostProcessorTest {
MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(sender = A_USER_ID, content = StateContent("", OtherState.RoomCreate))),
MatrixTimelineItem.Event("m.room.member", anEventTimelineItem(content = RoomMembershipContent(A_USER_ID_2, null, MembershipChange.JOINED))),
)
val processor = RoomBeginningPostProcessor()
val processor = RoomBeginningPostProcessor(mode)
val processedItems = processor.process(timelineItems, isDm = true, hasMoreToLoadBackwards = true)
assertThat(processedItems).isEqualTo(timelineItems)
}

Loading…
Cancel
Save