mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 13:38:49 +03:00
Make TimelineSettings aware of rootThreadEventId and welcome a new Thread mode for the timeline creation
This commit is contained in:
parent
50e51cbe29
commit
e541636802
8 changed files with 79 additions and 21 deletions
|
@ -27,5 +27,14 @@ data class TimelineSettings(
|
||||||
/**
|
/**
|
||||||
* If true, will build read receipts for each event.
|
* If true, will build read receipts for each event.
|
||||||
*/
|
*/
|
||||||
val buildReadReceipts: Boolean = true
|
val buildReadReceipts: Boolean = true,
|
||||||
)
|
/**
|
||||||
|
* The root thread eventId if this is a thread timeline, or null if this is NOT a thread timeline
|
||||||
|
*/
|
||||||
|
val rootThreadEventId: String? = null) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this is a thread timeline or false otherwise
|
||||||
|
*/
|
||||||
|
fun isThreadTimeline() = rootThreadEventId != null
|
||||||
|
}
|
||||||
|
|
|
@ -136,7 +136,7 @@ internal class DefaultTimeline(private val roomId: String,
|
||||||
ensureReadReceiptAreLoaded(realm)
|
ensureReadReceiptAreLoaded(realm)
|
||||||
backgroundRealm.set(realm)
|
backgroundRealm.set(realm)
|
||||||
listenToPostSnapshotSignals()
|
listenToPostSnapshotSignals()
|
||||||
openAround(initialEventId)
|
openAround(initialEventId, rootThreadEventId)
|
||||||
postSnapshot()
|
postSnapshot()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ internal class DefaultTimeline(private val roomId: String,
|
||||||
|
|
||||||
override fun restartWithEventId(eventId: String?) {
|
override fun restartWithEventId(eventId: String?) {
|
||||||
timelineScope.launch {
|
timelineScope.launch {
|
||||||
openAround(eventId)
|
openAround(eventId,rootThreadEventId)
|
||||||
postSnapshot()
|
postSnapshot()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,18 +226,20 @@ internal class DefaultTimeline(private val roomId: String,
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun openAround(eventId: String?) = withContext(timelineDispatcher) {
|
private suspend fun openAround(eventId: String?, rootThreadEventId: String?) = withContext(timelineDispatcher) {
|
||||||
val baseLogMessage = "openAround(eventId: $eventId)"
|
val baseLogMessage = "openAround(eventId: $eventId)"
|
||||||
Timber.v("$baseLogMessage started")
|
Timber.v("$baseLogMessage started")
|
||||||
if (!isStarted.get()) {
|
if (!isStarted.get()) {
|
||||||
throw IllegalStateException("You should call start before using timeline")
|
throw IllegalStateException("You should call start before using timeline")
|
||||||
}
|
}
|
||||||
strategy.onStop()
|
strategy.onStop()
|
||||||
strategy = if (eventId == null) {
|
|
||||||
buildStrategy(LoadTimelineStrategy.Mode.Live)
|
strategy = when {
|
||||||
} else {
|
rootThreadEventId != null -> buildStrategy(LoadTimelineStrategy.Mode.Thread(rootThreadEventId))
|
||||||
buildStrategy(LoadTimelineStrategy.Mode.Permalink(eventId))
|
eventId == null -> buildStrategy(LoadTimelineStrategy.Mode.Live)
|
||||||
|
else -> buildStrategy(LoadTimelineStrategy.Mode.Permalink(eventId))
|
||||||
}
|
}
|
||||||
|
|
||||||
initPaginationStates(eventId)
|
initPaginationStates(eventId)
|
||||||
strategy.onStart()
|
strategy.onStart()
|
||||||
loadMore(
|
loadMore(
|
||||||
|
|
|
@ -20,4 +20,5 @@ internal enum class LoadMoreResult {
|
||||||
REACHED_END,
|
REACHED_END,
|
||||||
SUCCESS,
|
SUCCESS,
|
||||||
FAILURE
|
FAILURE
|
||||||
|
// evenIDS
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ internal class LoadTimelineStrategy(
|
||||||
sealed interface Mode {
|
sealed interface Mode {
|
||||||
object Live : Mode
|
object Live : Mode
|
||||||
data class Permalink(val originEventId: String) : Mode
|
data class Permalink(val originEventId: String) : Mode
|
||||||
|
data class Thread(val rootThreadEventId: String) : Mode
|
||||||
|
|
||||||
fun originEventId(): String? {
|
fun originEventId(): String? {
|
||||||
return if (this is Permalink) {
|
return if (this is Permalink) {
|
||||||
|
@ -59,6 +60,14 @@ internal class LoadTimelineStrategy(
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fun getRootThreadEventId(): String? {
|
||||||
|
// return if (this is Thread) {
|
||||||
|
// rootThreadEventId
|
||||||
|
// } else {
|
||||||
|
// null
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Dependencies(
|
data class Dependencies(
|
||||||
|
@ -162,6 +171,7 @@ internal class LoadTimelineStrategy(
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun loadMore(count: Int, direction: Timeline.Direction, fetchOnServerIfNeeded: Boolean = true): LoadMoreResult {
|
suspend fun loadMore(count: Int, direction: Timeline.Direction, fetchOnServerIfNeeded: Boolean = true): LoadMoreResult {
|
||||||
|
///
|
||||||
if (mode is Mode.Permalink && timelineChunk == null) {
|
if (mode is Mode.Permalink && timelineChunk == null) {
|
||||||
val params = GetContextOfEventTask.Params(roomId, mode.originEventId)
|
val params = GetContextOfEventTask.Params(roomId, mode.originEventId)
|
||||||
try {
|
try {
|
||||||
|
@ -198,13 +208,22 @@ internal class LoadTimelineStrategy(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getChunkEntity(realm: Realm): RealmResults<ChunkEntity> {
|
private fun getChunkEntity(realm: Realm): RealmResults<ChunkEntity> {
|
||||||
return if (mode is Mode.Permalink) {
|
|
||||||
ChunkEntity.findAllIncludingEvents(realm, listOf(mode.originEventId))
|
return when (mode) {
|
||||||
} else {
|
is Mode.Live -> {
|
||||||
ChunkEntity.where(realm, roomId)
|
ChunkEntity.where(realm, roomId)
|
||||||
.equalTo(ChunkEntityFields.IS_LAST_FORWARD, true)
|
.equalTo(ChunkEntityFields.IS_LAST_FORWARD, true)
|
||||||
.findAll()
|
.findAll()
|
||||||
}
|
}
|
||||||
|
is Mode.Permalink -> {
|
||||||
|
ChunkEntity.findAllIncludingEvents(realm, listOf(mode.originEventId))
|
||||||
|
}
|
||||||
|
is Mode.Thread -> {
|
||||||
|
ChunkEntity.where(realm, roomId)
|
||||||
|
.equalTo(ChunkEntityFields.IS_LAST_FORWARD, true)
|
||||||
|
.findAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hasReachedLastForward(): Boolean {
|
private fun hasReachedLastForward(): Boolean {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import io.realm.RealmQuery
|
||||||
import io.realm.RealmResults
|
import io.realm.RealmResults
|
||||||
import io.realm.Sort
|
import io.realm.Sort
|
||||||
import kotlinx.coroutines.CompletableDeferred
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
|
import org.matrix.android.sdk.BuildConfig
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
|
@ -271,7 +272,24 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
||||||
private suspend fun loadFromStorage(count: Int, direction: Timeline.Direction): Int {
|
private suspend fun loadFromStorage(count: Int, direction: Timeline.Direction): Int {
|
||||||
val displayIndex = getNextDisplayIndex(direction) ?: return 0
|
val displayIndex = getNextDisplayIndex(direction) ?: return 0
|
||||||
val baseQuery = timelineEventEntities.where()
|
val baseQuery = timelineEventEntities.where()
|
||||||
val timelineEvents = baseQuery.offsets(direction, count, displayIndex).findAll().orEmpty()
|
|
||||||
|
val timelineEvents = if (timelineSettings.rootThreadEventId != null) {
|
||||||
|
baseQuery
|
||||||
|
.beginGroup()
|
||||||
|
.equalTo(TimelineEventEntityFields.ROOT.ROOT_THREAD_EVENT_ID, timelineSettings.rootThreadEventId)
|
||||||
|
.or()
|
||||||
|
.equalTo(TimelineEventEntityFields.ROOT.EVENT_ID, timelineSettings.rootThreadEventId)
|
||||||
|
.endGroup()
|
||||||
|
.offsets(direction, count, displayIndex)
|
||||||
|
.findAll()
|
||||||
|
.orEmpty()
|
||||||
|
} else {
|
||||||
|
baseQuery
|
||||||
|
.offsets(direction, count, displayIndex)
|
||||||
|
.findAll()
|
||||||
|
.orEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
if (timelineEvents.isEmpty()) return 0
|
if (timelineEvents.isEmpty()) return 0
|
||||||
fetchRootThreadEventsIfNeeded(timelineEvents)
|
fetchRootThreadEventsIfNeeded(timelineEvents)
|
||||||
if (direction == Timeline.Direction.FORWARDS) {
|
if (direction == Timeline.Direction.FORWARDS) {
|
||||||
|
@ -299,6 +317,7 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
||||||
* 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
|
||||||
*/
|
*/
|
||||||
private suspend fun fetchRootThreadEventsIfNeeded(offsetResults: List<TimelineEventEntity>) {
|
private suspend fun fetchRootThreadEventsIfNeeded(offsetResults: List<TimelineEventEntity>) {
|
||||||
|
if (BuildConfig.THREADING_ENABLED) return
|
||||||
val eventEntityList = offsetResults
|
val eventEntityList = offsetResults
|
||||||
.mapNotNull {
|
.mapNotNull {
|
||||||
it.root
|
it.root
|
||||||
|
|
|
@ -127,7 +127,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||||
private val invisibleEventsSource = BehaviorDataSource<RoomDetailAction.TimelineEventTurnsInvisible>()
|
private val invisibleEventsSource = BehaviorDataSource<RoomDetailAction.TimelineEventTurnsInvisible>()
|
||||||
private val visibleEventsSource = BehaviorDataSource<RoomDetailAction.TimelineEventTurnsVisible>()
|
private val visibleEventsSource = BehaviorDataSource<RoomDetailAction.TimelineEventTurnsVisible>()
|
||||||
private var timelineEvents = MutableSharedFlow<List<TimelineEvent>>(0)
|
private var timelineEvents = MutableSharedFlow<List<TimelineEvent>>(0)
|
||||||
val timeline = timelineFactory.createTimeline(viewModelScope, room, eventId)
|
val timeline = timelineFactory.createTimeline(viewModelScope, room, eventId, initialState.rootThreadEventId)
|
||||||
|
|
||||||
// Same lifecycle than the ViewModel (survive to screen rotation)
|
// Same lifecycle than the ViewModel (survive to screen rotation)
|
||||||
val previewUrlRetriever = PreviewUrlRetriever(session, viewModelScope)
|
val previewUrlRetriever = PreviewUrlRetriever(session, viewModelScope)
|
||||||
|
|
|
@ -35,8 +35,14 @@ private val secondaryTimelineAllowedTypes = listOf(
|
||||||
|
|
||||||
class TimelineFactory @Inject constructor(private val session: Session, private val timelineSettingsFactory: TimelineSettingsFactory) {
|
class TimelineFactory @Inject constructor(private val session: Session, private val timelineSettingsFactory: TimelineSettingsFactory) {
|
||||||
|
|
||||||
fun createTimeline(coroutineScope: CoroutineScope, mainRoom: Room, eventId: String?): Timeline {
|
fun createTimeline(
|
||||||
val settings = timelineSettingsFactory.create()
|
coroutineScope: CoroutineScope,
|
||||||
|
mainRoom: Room,
|
||||||
|
eventId: String?,
|
||||||
|
rootThreadEventId: String?
|
||||||
|
): Timeline {
|
||||||
|
val settings = timelineSettingsFactory.create(rootThreadEventId)
|
||||||
|
|
||||||
if (!session.vectorCallService.protocolChecker.supportVirtualRooms) {
|
if (!session.vectorCallService.protocolChecker.supportVirtualRooms) {
|
||||||
return mainRoom.createTimeline(eventId, settings)
|
return mainRoom.createTimeline(eventId, settings)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,11 @@ import javax.inject.Inject
|
||||||
|
|
||||||
class TimelineSettingsFactory @Inject constructor(private val userPreferencesProvider: UserPreferencesProvider) {
|
class TimelineSettingsFactory @Inject constructor(private val userPreferencesProvider: UserPreferencesProvider) {
|
||||||
|
|
||||||
fun create(): TimelineSettings {
|
fun create(rootThreadEventId: String?): TimelineSettings {
|
||||||
return TimelineSettings(
|
return TimelineSettings(
|
||||||
initialSize = 30,
|
initialSize = 30,
|
||||||
buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts())
|
buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts(),
|
||||||
|
rootThreadEventId = rootThreadEventId
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue