mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
Refactor threads to support the new timeline implementation
This commit is contained in:
parent
1b41a72e72
commit
37ec3fdf84
@ -93,7 +93,7 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
handleDatabaseChangeSet(frozenResults, changeSet)
|
handleDatabaseChangeSet(frozenResults, changeSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var timelineEventEntities: RealmResults<TimelineEventEntity> = chunkEntity.sortedTimelineEvents()
|
private var timelineEventEntities: RealmResults<TimelineEventEntity> = chunkEntity.sortedTimelineEvents(timelineSettings.rootThreadEventId)
|
||||||
private val builtEvents: MutableList<TimelineEvent> = Collections.synchronizedList(ArrayList())
|
private val builtEvents: MutableList<TimelineEvent> = Collections.synchronizedList(ArrayList())
|
||||||
private val builtEventsIndexes: MutableMap<String, Int> = Collections.synchronizedMap(HashMap<String, Int>())
|
private val builtEventsIndexes: MutableMap<String, Int> = Collections.synchronizedMap(HashMap<String, Int>())
|
||||||
|
|
||||||
@ -138,13 +138,18 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
} else if (direction == Timeline.Direction.BACKWARDS && prevChunk != null) {
|
} else if (direction == Timeline.Direction.BACKWARDS && prevChunk != null) {
|
||||||
return prevChunk?.loadMore(count, direction, fetchOnServerIfNeeded) ?: LoadMoreResult.FAILURE
|
return prevChunk?.loadMore(count, direction, fetchOnServerIfNeeded) ?: LoadMoreResult.FAILURE
|
||||||
}
|
}
|
||||||
val loadFromStorageCount = loadFromStorage(count, direction)
|
val loadFromStorage = loadFromStorage(count, direction).also{
|
||||||
Timber.v("Has loaded $loadFromStorageCount items from storage in $direction")
|
logLoadedFromStorage(it,direction)
|
||||||
val offsetCount = count - loadFromStorageCount
|
}
|
||||||
|
|
||||||
|
val offsetCount = count - loadFromStorage.numberOfEvents
|
||||||
|
|
||||||
return if (direction == Timeline.Direction.FORWARDS && isLastForward.get()) {
|
return if (direction == Timeline.Direction.FORWARDS && isLastForward.get()) {
|
||||||
LoadMoreResult.REACHED_END
|
LoadMoreResult.REACHED_END
|
||||||
} else if (direction == Timeline.Direction.BACKWARDS && isLastBackward.get()) {
|
} else if (direction == Timeline.Direction.BACKWARDS && isLastBackward.get()) {
|
||||||
LoadMoreResult.REACHED_END
|
LoadMoreResult.REACHED_END
|
||||||
|
} else if (timelineSettings.isThreadTimeline() && loadFromStorage.threadReachedEnd) {
|
||||||
|
LoadMoreResult.REACHED_END
|
||||||
} else if (offsetCount == 0) {
|
} else if (offsetCount == 0) {
|
||||||
LoadMoreResult.SUCCESS
|
LoadMoreResult.SUCCESS
|
||||||
} else {
|
} else {
|
||||||
@ -188,6 +193,15 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple log that displays the number and timeline of loaded events
|
||||||
|
*/
|
||||||
|
private fun logLoadedFromStorage(loadedFromStorage: LoadedFromStorage, direction: Timeline.Direction) =
|
||||||
|
Timber.v("[" +
|
||||||
|
"${if (timelineSettings.isThreadTimeline()) "ThreadTimeLine" else "Timeline"}] Has loaded " +
|
||||||
|
"${loadedFromStorage.numberOfEvents} items from storage in $direction " +
|
||||||
|
if (timelineSettings.isThreadTimeline() && loadedFromStorage.threadReachedEnd) "[Reached End]" else "")
|
||||||
|
|
||||||
fun getBuiltEventIndex(eventId: String, searchInNext: Boolean, searchInPrev: Boolean): Int? {
|
fun getBuiltEventIndex(eventId: String, searchInNext: Boolean, searchInPrev: Boolean): Int? {
|
||||||
val builtEventIndex = builtEventsIndexes[eventId]
|
val builtEventIndex = builtEventsIndexes[eventId]
|
||||||
if (builtEventIndex != null) {
|
if (builtEventIndex != null) {
|
||||||
@ -268,29 +282,31 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method tries to read events from the current chunk.
|
* This method tries to read events from the current chunk.
|
||||||
|
* @return the number of events loaded. If we are in a thread timeline it also returns
|
||||||
|
* whether or not we reached the end/root message
|
||||||
*/
|
*/
|
||||||
private suspend fun loadFromStorage(count: Int, direction: Timeline.Direction): Int {
|
private suspend fun loadFromStorage(count: Int, direction: Timeline.Direction): LoadedFromStorage {
|
||||||
val displayIndex = getNextDisplayIndex(direction) ?: return 0
|
val displayIndex = getNextDisplayIndex(direction) ?: return LoadedFromStorage()
|
||||||
val baseQuery = timelineEventEntities.where()
|
val baseQuery = timelineEventEntities.where()
|
||||||
|
|
||||||
val timelineEvents = if (timelineSettings.rootThreadEventId != null) {
|
// val timelineEvents = if (timelineSettings.rootThreadEventId != null) {
|
||||||
baseQuery
|
// baseQuery
|
||||||
.beginGroup()
|
// .beginGroup()
|
||||||
.equalTo(TimelineEventEntityFields.ROOT.ROOT_THREAD_EVENT_ID, timelineSettings.rootThreadEventId)
|
// .equalTo(TimelineEventEntityFields.ROOT.ROOT_THREAD_EVENT_ID, timelineSettings.rootThreadEventId)
|
||||||
.or()
|
// .or()
|
||||||
.equalTo(TimelineEventEntityFields.ROOT.EVENT_ID, timelineSettings.rootThreadEventId)
|
// .equalTo(TimelineEventEntityFields.ROOT.EVENT_ID, timelineSettings.rootThreadEventId)
|
||||||
.endGroup()
|
// .endGroup()
|
||||||
|
// .offsets(direction, count, displayIndex)
|
||||||
|
// .findAll()
|
||||||
|
// .orEmpty()
|
||||||
|
// } else {
|
||||||
|
val timelineEvents = baseQuery
|
||||||
.offsets(direction, count, displayIndex)
|
.offsets(direction, count, displayIndex)
|
||||||
.findAll()
|
.findAll()
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
} else {
|
// }
|
||||||
baseQuery
|
|
||||||
.offsets(direction, count, displayIndex)
|
|
||||||
.findAll()
|
|
||||||
.orEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timelineEvents.isEmpty()) return 0
|
if (timelineEvents.isEmpty()) return LoadedFromStorage()
|
||||||
fetchRootThreadEventsIfNeeded(timelineEvents)
|
fetchRootThreadEventsIfNeeded(timelineEvents)
|
||||||
if (direction == Timeline.Direction.FORWARDS) {
|
if (direction == Timeline.Direction.FORWARDS) {
|
||||||
builtEventsIndexes.entries.forEach { it.setValue(it.value + timelineEvents.size) }
|
builtEventsIndexes.entries.forEach { it.setValue(it.value + timelineEvents.size) }
|
||||||
@ -309,9 +325,20 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
builtEvents.add(timelineEvent)
|
builtEvents.add(timelineEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return timelineEvents.size
|
return LoadedFromStorage(
|
||||||
|
threadReachedEnd = threadReachedEnd(timelineEvents),
|
||||||
|
numberOfEvents = timelineEvents.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not the the thread has reached end. It returned false if the current timeline
|
||||||
|
* is not a thread timeline
|
||||||
|
*/
|
||||||
|
private fun threadReachedEnd(timelineEvents: List<TimelineEventEntity>): Boolean =
|
||||||
|
timelineSettings.rootThreadEventId?.let { rootThreadId ->
|
||||||
|
timelineEvents.firstOrNull { it.eventId == rootThreadId }?.let { true }
|
||||||
|
} ?: false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is responsible to fetch and store the root event of a thread event
|
* This function is responsible to fetch and store the root event of a thread event
|
||||||
* in order to be able to display the event to the user appropriately
|
* in order to be able to display the event to the user appropriately
|
||||||
@ -362,7 +389,8 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
val loadMoreResult = try {
|
val loadMoreResult = try {
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
if (direction == Timeline.Direction.BACKWARDS || !chunkEntity.hasBeenALastForwardChunk()) return LoadMoreResult.REACHED_END
|
if (direction == Timeline.Direction.BACKWARDS || !chunkEntity.hasBeenALastForwardChunk()) return LoadMoreResult.REACHED_END
|
||||||
val lastKnownEventId = chunkEntity.sortedTimelineEvents().firstOrNull()?.eventId ?: return LoadMoreResult.FAILURE
|
val lastKnownEventId = chunkEntity.sortedTimelineEvents(timelineSettings.rootThreadEventId).firstOrNull()?.eventId
|
||||||
|
?: return LoadMoreResult.FAILURE
|
||||||
val taskParams = FetchTokenAndPaginateTask.Params(roomId, lastKnownEventId, direction.toPaginationDirection(), count)
|
val taskParams = FetchTokenAndPaginateTask.Params(roomId, lastKnownEventId, direction.toPaginationDirection(), count)
|
||||||
fetchTokenAndPaginateTask.execute(taskParams).toLoadMoreResult()
|
fetchTokenAndPaginateTask.execute(taskParams).toLoadMoreResult()
|
||||||
} else {
|
} else {
|
||||||
@ -473,6 +501,11 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
onBuiltEvents = this.onBuiltEvents
|
onBuiltEvents = this.onBuiltEvents
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private data class LoadedFromStorage(
|
||||||
|
val threadReachedEnd: Boolean = false,
|
||||||
|
val numberOfEvents: Int = 0
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun RealmQuery<TimelineEventEntity>.offsets(
|
private fun RealmQuery<TimelineEventEntity>.offsets(
|
||||||
@ -493,6 +526,19 @@ private fun Timeline.Direction.toPaginationDirection(): PaginationDirection {
|
|||||||
return if (this == Timeline.Direction.BACKWARDS) PaginationDirection.BACKWARDS else PaginationDirection.FORWARDS
|
return if (this == Timeline.Direction.BACKWARDS) PaginationDirection.BACKWARDS else PaginationDirection.FORWARDS
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ChunkEntity.sortedTimelineEvents(): RealmResults<TimelineEventEntity> {
|
private fun ChunkEntity.sortedTimelineEvents(rootThreadEventId: String?): RealmResults<TimelineEventEntity> {
|
||||||
return timelineEvents.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)
|
return if (rootThreadEventId == null) {
|
||||||
|
timelineEvents
|
||||||
|
.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)
|
||||||
|
} else {
|
||||||
|
timelineEvents
|
||||||
|
.where()
|
||||||
|
.beginGroup()
|
||||||
|
.equalTo(TimelineEventEntityFields.ROOT.ROOT_THREAD_EVENT_ID, rootThreadEventId)
|
||||||
|
.or()
|
||||||
|
.equalTo(TimelineEventEntityFields.ROOT.EVENT_ID, rootThreadEventId)
|
||||||
|
.endGroup()
|
||||||
|
.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)
|
||||||
|
.findAll()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ import org.matrix.android.sdk.api.session.room.send.SendState
|
|||||||
import org.matrix.android.sdk.internal.database.helper.addIfNecessary
|
import org.matrix.android.sdk.internal.database.helper.addIfNecessary
|
||||||
import org.matrix.android.sdk.internal.database.helper.addStateEvent
|
import org.matrix.android.sdk.internal.database.helper.addStateEvent
|
||||||
import org.matrix.android.sdk.internal.database.helper.addTimelineEvent
|
import org.matrix.android.sdk.internal.database.helper.addTimelineEvent
|
||||||
import org.matrix.android.sdk.internal.database.helper.merge
|
|
||||||
import org.matrix.android.sdk.internal.database.helper.updateThreadSummaryIfNeeded
|
import org.matrix.android.sdk.internal.database.helper.updateThreadSummaryIfNeeded
|
||||||
import org.matrix.android.sdk.internal.database.mapper.toEntity
|
import org.matrix.android.sdk.internal.database.mapper.toEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.ChunkEntity
|
import org.matrix.android.sdk.internal.database.model.ChunkEntity
|
||||||
|
Loading…
Reference in New Issue
Block a user