mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-25 19:05:56 +03:00
Fix some issues and make test passes
This commit is contained in:
parent
f454078c6b
commit
1728d31401
9 changed files with 112 additions and 118 deletions
|
@ -241,6 +241,11 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
|
||||||
|
|
||||||
val bobEventsListener = object : Timeline.Listener {
|
val bobEventsListener = object : Timeline.Listener {
|
||||||
override fun onTimelineFailure(throwable: Throwable) {
|
override fun onTimelineFailure(throwable: Throwable) {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNewTimelineEvents(eventIds: List<String>) {
|
||||||
|
// noop
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
|
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
|
||||||
|
|
|
@ -20,15 +20,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
import im.vector.matrix.android.InstrumentedTest
|
import im.vector.matrix.android.InstrumentedTest
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.internal.database.helper.add
|
import im.vector.matrix.android.api.session.room.send.SendState
|
||||||
import im.vector.matrix.android.internal.database.helper.lastStateIndex
|
import im.vector.matrix.android.internal.database.helper.addTimelineEvent
|
||||||
import im.vector.matrix.android.internal.database.helper.merge
|
import im.vector.matrix.android.internal.database.helper.merge
|
||||||
|
import im.vector.matrix.android.internal.database.mapper.toEntity
|
||||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||||
import im.vector.matrix.android.internal.database.model.SessionRealmModule
|
import im.vector.matrix.android.internal.database.model.SessionRealmModule
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
||||||
import im.vector.matrix.android.session.room.timeline.RoomDataHelper.createFakeListOfEvents
|
import im.vector.matrix.android.session.room.timeline.RoomDataHelper.createFakeListOfEvents
|
||||||
import im.vector.matrix.android.session.room.timeline.RoomDataHelper.createFakeMessageEvent
|
import im.vector.matrix.android.session.room.timeline.RoomDataHelper.createFakeMessageEvent
|
||||||
import im.vector.matrix.android.session.room.timeline.RoomDataHelper.createFakeRoomMemberEvent
|
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmConfiguration
|
import io.realm.RealmConfiguration
|
||||||
import io.realm.kotlin.createObject
|
import io.realm.kotlin.createObject
|
||||||
|
@ -58,8 +58,11 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||||
fun add_shouldAdd_whenNotAlreadyIncluded() {
|
fun add_shouldAdd_whenNotAlreadyIncluded() {
|
||||||
monarchy.runTransactionSync { realm ->
|
monarchy.runTransactionSync { realm ->
|
||||||
val chunk: ChunkEntity = realm.createObject()
|
val chunk: ChunkEntity = realm.createObject()
|
||||||
val fakeEvent = createFakeMessageEvent()
|
|
||||||
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
|
val fakeEvent = createFakeMessageEvent().toEntity(ROOM_ID, SendState.SYNCED).let {
|
||||||
|
realm.copyToRealmOrUpdate(it)
|
||||||
|
}
|
||||||
|
chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap())
|
||||||
chunk.timelineEvents.size shouldEqual 1
|
chunk.timelineEvents.size shouldEqual 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,65 +71,23 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||||
fun add_shouldNotAdd_whenAlreadyIncluded() {
|
fun add_shouldNotAdd_whenAlreadyIncluded() {
|
||||||
monarchy.runTransactionSync { realm ->
|
monarchy.runTransactionSync { realm ->
|
||||||
val chunk: ChunkEntity = realm.createObject()
|
val chunk: ChunkEntity = realm.createObject()
|
||||||
val fakeEvent = createFakeMessageEvent()
|
val fakeEvent = createFakeMessageEvent().toEntity(ROOM_ID, SendState.SYNCED).let {
|
||||||
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
|
realm.copyToRealmOrUpdate(it)
|
||||||
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
|
}
|
||||||
|
chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap())
|
||||||
|
chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap())
|
||||||
chunk.timelineEvents.size shouldEqual 1
|
chunk.timelineEvents.size shouldEqual 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun add_shouldStateIndexIncremented_whenStateEventIsAddedForward() {
|
|
||||||
monarchy.runTransactionSync { realm ->
|
|
||||||
val chunk: ChunkEntity = realm.createObject()
|
|
||||||
val fakeEvent = createFakeRoomMemberEvent()
|
|
||||||
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
|
|
||||||
chunk.lastStateIndex(PaginationDirection.FORWARDS) shouldEqual 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun add_shouldStateIndexNotIncremented_whenNoStateEventIsAdded() {
|
|
||||||
monarchy.runTransactionSync { realm ->
|
|
||||||
val chunk: ChunkEntity = realm.createObject()
|
|
||||||
val fakeEvent = createFakeMessageEvent()
|
|
||||||
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
|
|
||||||
chunk.lastStateIndex(PaginationDirection.FORWARDS) shouldEqual 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun addAll_shouldStateIndexIncremented_whenStateEventsAreAddedForward() {
|
|
||||||
monarchy.runTransactionSync { realm ->
|
|
||||||
val chunk: ChunkEntity = realm.createObject()
|
|
||||||
val fakeEvents = createFakeListOfEvents(30)
|
|
||||||
val numberOfStateEvents = fakeEvents.filter { it.isStateEvent() }.size
|
|
||||||
chunk.addAll("roomId", fakeEvents, PaginationDirection.FORWARDS)
|
|
||||||
chunk.lastStateIndex(PaginationDirection.FORWARDS) shouldEqual numberOfStateEvents
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun addAll_shouldStateIndexDecremented_whenStateEventsAreAddedBackward() {
|
|
||||||
monarchy.runTransactionSync { realm ->
|
|
||||||
val chunk: ChunkEntity = realm.createObject()
|
|
||||||
val fakeEvents = createFakeListOfEvents(30)
|
|
||||||
val numberOfStateEvents = fakeEvents.filter { it.isStateEvent() }.size
|
|
||||||
val lastIsState = fakeEvents.last().isStateEvent()
|
|
||||||
val expectedStateIndex = if (lastIsState) -numberOfStateEvents + 1 else -numberOfStateEvents
|
|
||||||
chunk.addAll("roomId", fakeEvents, PaginationDirection.BACKWARDS)
|
|
||||||
chunk.lastStateIndex(PaginationDirection.BACKWARDS) shouldEqual expectedStateIndex
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun merge_shouldAddEvents_whenMergingBackward() {
|
fun merge_shouldAddEvents_whenMergingBackward() {
|
||||||
monarchy.runTransactionSync { realm ->
|
monarchy.runTransactionSync { realm ->
|
||||||
val chunk1: ChunkEntity = realm.createObject()
|
val chunk1: ChunkEntity = realm.createObject()
|
||||||
val chunk2: ChunkEntity = realm.createObject()
|
val chunk2: ChunkEntity = realm.createObject()
|
||||||
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||||
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||||
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
|
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
|
||||||
chunk1.timelineEvents.size shouldEqual 60
|
chunk1.timelineEvents.size shouldEqual 60
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,9 +101,9 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||||
val eventsForChunk2 = eventsForChunk1 + createFakeListOfEvents(10)
|
val eventsForChunk2 = eventsForChunk1 + createFakeListOfEvents(10)
|
||||||
chunk1.isLastForward = true
|
chunk1.isLastForward = true
|
||||||
chunk2.isLastForward = false
|
chunk2.isLastForward = false
|
||||||
chunk1.addAll("roomId", eventsForChunk1, PaginationDirection.FORWARDS)
|
chunk1.addAll(ROOM_ID, eventsForChunk1, PaginationDirection.FORWARDS)
|
||||||
chunk2.addAll("roomId", eventsForChunk2, PaginationDirection.BACKWARDS)
|
chunk2.addAll(ROOM_ID, eventsForChunk2, PaginationDirection.BACKWARDS)
|
||||||
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
|
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
|
||||||
chunk1.timelineEvents.size shouldEqual 40
|
chunk1.timelineEvents.size shouldEqual 40
|
||||||
chunk1.isLastForward.shouldBeTrue()
|
chunk1.isLastForward.shouldBeTrue()
|
||||||
}
|
}
|
||||||
|
@ -155,9 +116,9 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||||
val chunk2: ChunkEntity = realm.createObject()
|
val chunk2: ChunkEntity = realm.createObject()
|
||||||
val prevToken = "prev_token"
|
val prevToken = "prev_token"
|
||||||
chunk1.prevToken = prevToken
|
chunk1.prevToken = prevToken
|
||||||
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||||
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||||
chunk1.merge("roomId", chunk2, PaginationDirection.FORWARDS)
|
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.FORWARDS)
|
||||||
chunk1.prevToken shouldEqual prevToken
|
chunk1.prevToken shouldEqual prevToken
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,19 +130,25 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||||
val chunk2: ChunkEntity = realm.createObject()
|
val chunk2: ChunkEntity = realm.createObject()
|
||||||
val nextToken = "next_token"
|
val nextToken = "next_token"
|
||||||
chunk1.nextToken = nextToken
|
chunk1.nextToken = nextToken
|
||||||
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||||
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||||
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
|
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
|
||||||
chunk1.nextToken shouldEqual nextToken
|
chunk1.nextToken shouldEqual nextToken
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ChunkEntity.addAll(roomId: String,
|
private fun ChunkEntity.addAll(roomId: String,
|
||||||
events: List<Event>,
|
events: List<Event>,
|
||||||
direction: PaginationDirection,
|
direction: PaginationDirection) {
|
||||||
stateIndexOffset: Int = 0) {
|
|
||||||
events.forEach { event ->
|
events.forEach { event ->
|
||||||
add(roomId, event, direction)
|
val fakeEvent = event.toEntity(roomId, SendState.SYNCED).let {
|
||||||
|
realm.copyToRealmOrUpdate(it)
|
||||||
|
}
|
||||||
|
addTimelineEvent(roomId, fakeEvent, direction, emptyMap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ROOM_ID = "roomId"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,27 +62,7 @@ internal fun ChunkEntity.merge(roomId: String, chunkToMerge: ChunkEntity, direct
|
||||||
}
|
}
|
||||||
return eventsToMerge
|
return eventsToMerge
|
||||||
.forEach {
|
.forEach {
|
||||||
if (timelineEvents.find(it.eventId) == null) {
|
addTimelineEventFromMerge(localRealm, it, direction)
|
||||||
val eventId = it.eventId
|
|
||||||
if (timelineEvents.find(eventId) != null) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val displayIndex = nextDisplayIndex(direction)
|
|
||||||
val localId = TimelineEventEntity.nextId(realm)
|
|
||||||
val copied = localRealm.createObject<TimelineEventEntity>().apply {
|
|
||||||
this.localId = localId
|
|
||||||
this.root = it.root
|
|
||||||
this.eventId = it.eventId
|
|
||||||
this.roomId = it.roomId
|
|
||||||
this.annotations = it.annotations
|
|
||||||
this.readReceipts = it.readReceipts
|
|
||||||
this.displayIndex = displayIndex
|
|
||||||
this.senderAvatar = it.senderAvatar
|
|
||||||
this.senderName = it.senderName
|
|
||||||
this.isUniqueDisplayName = it.isUniqueDisplayName
|
|
||||||
}
|
|
||||||
timelineEvents.add(copied)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +88,7 @@ internal fun ChunkEntity.addStateEvent(roomId: String, stateEvent: EventEntity,
|
||||||
internal fun ChunkEntity.addTimelineEvent(roomId: String,
|
internal fun ChunkEntity.addTimelineEvent(roomId: String,
|
||||||
eventEntity: EventEntity,
|
eventEntity: EventEntity,
|
||||||
direction: PaginationDirection,
|
direction: PaginationDirection,
|
||||||
roomMemberContentsByUser: HashMap<String, RoomMemberContent?>) {
|
roomMemberContentsByUser: Map<String, RoomMemberContent?>) {
|
||||||
val eventId = eventEntity.eventId
|
val eventId = eventEntity.eventId
|
||||||
if (timelineEvents.find(eventId) != null) {
|
if (timelineEvents.find(eventId) != null) {
|
||||||
return
|
return
|
||||||
|
@ -130,28 +110,60 @@ internal fun ChunkEntity.addTimelineEvent(roomId: String,
|
||||||
val roomMemberContent = roomMemberContentsByUser[senderId]
|
val roomMemberContent = roomMemberContentsByUser[senderId]
|
||||||
this.senderAvatar = roomMemberContent?.avatarUrl
|
this.senderAvatar = roomMemberContent?.avatarUrl
|
||||||
this.senderName = roomMemberContent?.displayName
|
this.senderName = roomMemberContent?.displayName
|
||||||
if (roomMemberContent?.displayName != null) {
|
isUniqueDisplayName = if (roomMemberContent?.displayName != null) {
|
||||||
val isHistoricalUnique = roomMemberContentsByUser.values.find {
|
computeIsUnique(realm, roomId, isLastForward, roomMemberContent, roomMemberContentsByUser)
|
||||||
it != roomMemberContent && it?.displayName == roomMemberContent.displayName
|
|
||||||
} == null
|
|
||||||
isUniqueDisplayName = if (isLastForward) {
|
|
||||||
val isLiveUnique = RoomMemberSummaryEntity
|
|
||||||
.where(realm, roomId)
|
|
||||||
.equalTo(RoomMemberSummaryEntityFields.DISPLAY_NAME, roomMemberContent.displayName)
|
|
||||||
.findAll().none {
|
|
||||||
!roomMemberContentsByUser.containsKey(it.userId)
|
|
||||||
}
|
|
||||||
isHistoricalUnique && isLiveUnique
|
|
||||||
} else {
|
|
||||||
isHistoricalUnique
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
isUniqueDisplayName = true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timelineEvents.add(timelineEventEntity)
|
timelineEvents.add(timelineEventEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun computeIsUnique(
|
||||||
|
realm: Realm,
|
||||||
|
roomId: String,
|
||||||
|
isLastForward: Boolean,
|
||||||
|
myRoomMemberContent: RoomMemberContent,
|
||||||
|
roomMemberContentsByUser: Map<String, RoomMemberContent?>
|
||||||
|
): Boolean {
|
||||||
|
val isHistoricalUnique = roomMemberContentsByUser.values.find {
|
||||||
|
it != myRoomMemberContent && it?.displayName == myRoomMemberContent.displayName
|
||||||
|
} == null
|
||||||
|
return if (isLastForward) {
|
||||||
|
val isLiveUnique = RoomMemberSummaryEntity
|
||||||
|
.where(realm, roomId)
|
||||||
|
.equalTo(RoomMemberSummaryEntityFields.DISPLAY_NAME, myRoomMemberContent.displayName)
|
||||||
|
.findAll().none {
|
||||||
|
!roomMemberContentsByUser.containsKey(it.userId)
|
||||||
|
}
|
||||||
|
isHistoricalUnique && isLiveUnique
|
||||||
|
} else {
|
||||||
|
isHistoricalUnique
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ChunkEntity.addTimelineEventFromMerge(realm: Realm, timelineEventEntity: TimelineEventEntity, direction: PaginationDirection) {
|
||||||
|
val eventId = timelineEventEntity.eventId
|
||||||
|
if (timelineEvents.find(eventId) != null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val displayIndex = nextDisplayIndex(direction)
|
||||||
|
val localId = TimelineEventEntity.nextId(realm)
|
||||||
|
val copied = realm.createObject<TimelineEventEntity>().apply {
|
||||||
|
this.localId = localId
|
||||||
|
this.root = timelineEventEntity.root
|
||||||
|
this.eventId = timelineEventEntity.eventId
|
||||||
|
this.roomId = timelineEventEntity.roomId
|
||||||
|
this.annotations = timelineEventEntity.annotations
|
||||||
|
this.readReceipts = timelineEventEntity.readReceipts
|
||||||
|
this.displayIndex = displayIndex
|
||||||
|
this.senderAvatar = timelineEventEntity.senderAvatar
|
||||||
|
this.senderName = timelineEventEntity.senderName
|
||||||
|
this.isUniqueDisplayName = timelineEventEntity.isUniqueDisplayName
|
||||||
|
}
|
||||||
|
timelineEvents.add(copied)
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleReadReceipts(realm: Realm, roomId: String, eventEntity: EventEntity, senderId: String): ReadReceiptsSummaryEntity {
|
private fun handleReadReceipts(realm: Realm, roomId: String, eventEntity: EventEntity, senderId: String): ReadReceiptsSummaryEntity {
|
||||||
val readReceiptsSummaryEntity = ReadReceiptsSummaryEntity.where(realm, eventEntity.eventId).findFirst()
|
val readReceiptsSummaryEntity = ReadReceiptsSummaryEntity.where(realm, eventEntity.eventId).findFirst()
|
||||||
?: realm.createObject<ReadReceiptsSummaryEntity>(eventEntity.eventId).apply {
|
?: realm.createObject<ReadReceiptsSummaryEntity>(eventEntity.eventId).apply {
|
||||||
|
|
|
@ -20,7 +20,6 @@ import androidx.annotation.WorkerThread
|
||||||
import im.vector.matrix.android.internal.session.SessionScope
|
import im.vector.matrix.android.internal.session.SessionScope
|
||||||
import im.vector.matrix.android.internal.session.homeserver.HomeServerPinger
|
import im.vector.matrix.android.internal.session.homeserver.HomeServerPinger
|
||||||
import im.vector.matrix.android.internal.util.BackgroundDetectionObserver
|
import im.vector.matrix.android.internal.util.BackgroundDetectionObserver
|
||||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
|
@ -120,7 +120,7 @@ internal class DefaultTimeline(
|
||||||
if (!results.isLoaded || !results.isValid) {
|
if (!results.isLoaded || !results.isValid) {
|
||||||
return@OrderedRealmCollectionChangeListener
|
return@OrderedRealmCollectionChangeListener
|
||||||
}
|
}
|
||||||
handleUpdates(changeSet)
|
handleUpdates(results, changeSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val relationsListener = OrderedRealmCollectionChangeListener<RealmResults<EventAnnotationsSummaryEntity>> { collection, changeSet ->
|
private val relationsListener = OrderedRealmCollectionChangeListener<RealmResults<EventAnnotationsSummaryEntity>> { collection, changeSet ->
|
||||||
|
@ -185,7 +185,7 @@ internal class DefaultTimeline(
|
||||||
.filterEventsWithSettings()
|
.filterEventsWithSettings()
|
||||||
.findAll()
|
.findAll()
|
||||||
handleInitialLoad()
|
handleInitialLoad()
|
||||||
filteredEvents.addChangeListener(eventsChangeListener)
|
nonFilteredEvents.addChangeListener(eventsChangeListener)
|
||||||
|
|
||||||
eventRelations = EventAnnotationsSummaryEntity.whereInRoom(realm, roomId)
|
eventRelations = EventAnnotationsSummaryEntity.whereInRoom(realm, roomId)
|
||||||
.findAllAsync()
|
.findAllAsync()
|
||||||
|
@ -215,8 +215,8 @@ internal class DefaultTimeline(
|
||||||
if (this::eventRelations.isInitialized) {
|
if (this::eventRelations.isInitialized) {
|
||||||
eventRelations.removeAllChangeListeners()
|
eventRelations.removeAllChangeListeners()
|
||||||
}
|
}
|
||||||
if (this::filteredEvents.isInitialized) {
|
if (this::nonFilteredEvents.isInitialized) {
|
||||||
filteredEvents.removeAllChangeListeners()
|
nonFilteredEvents.removeAllChangeListeners()
|
||||||
}
|
}
|
||||||
if (settings.shouldHandleHiddenReadReceipts()) {
|
if (settings.shouldHandleHiddenReadReceipts()) {
|
||||||
hiddenReadReceipts.dispose()
|
hiddenReadReceipts.dispose()
|
||||||
|
@ -452,7 +452,7 @@ internal class DefaultTimeline(
|
||||||
var shouldFetchInitialEvent = false
|
var shouldFetchInitialEvent = false
|
||||||
val currentInitialEventId = initialEventId
|
val currentInitialEventId = initialEventId
|
||||||
val initialDisplayIndex = if (currentInitialEventId == null) {
|
val initialDisplayIndex = if (currentInitialEventId == null) {
|
||||||
filteredEvents.firstOrNull()?.displayIndex
|
nonFilteredEvents.firstOrNull()?.displayIndex
|
||||||
} else {
|
} else {
|
||||||
val initialEvent = nonFilteredEvents.where()
|
val initialEvent = nonFilteredEvents.where()
|
||||||
.equalTo(TimelineEventEntityFields.EVENT_ID, initialEventId)
|
.equalTo(TimelineEventEntityFields.EVENT_ID, initialEventId)
|
||||||
|
@ -480,7 +480,7 @@ internal class DefaultTimeline(
|
||||||
/**
|
/**
|
||||||
* This has to be called on TimelineThread as it access realm live results
|
* This has to be called on TimelineThread as it access realm live results
|
||||||
*/
|
*/
|
||||||
private fun handleUpdates(changeSet: OrderedCollectionChangeSet) {
|
private fun handleUpdates(results: RealmResults<TimelineEventEntity>, changeSet: OrderedCollectionChangeSet) {
|
||||||
// If changeSet has deletion we are having a gap, so we clear everything
|
// If changeSet has deletion we are having a gap, so we clear everything
|
||||||
if (changeSet.deletionRanges.isNotEmpty()) {
|
if (changeSet.deletionRanges.isNotEmpty()) {
|
||||||
clearAllValues()
|
clearAllValues()
|
||||||
|
@ -488,9 +488,9 @@ internal class DefaultTimeline(
|
||||||
var postSnapshot = false
|
var postSnapshot = false
|
||||||
changeSet.insertionRanges.forEach { range ->
|
changeSet.insertionRanges.forEach { range ->
|
||||||
val (startDisplayIndex, direction) = if (range.startIndex == 0) {
|
val (startDisplayIndex, direction) = if (range.startIndex == 0) {
|
||||||
Pair(filteredEvents[range.length - 1]!!.displayIndex, Timeline.Direction.FORWARDS)
|
Pair(results[range.length - 1]!!.displayIndex, Timeline.Direction.FORWARDS)
|
||||||
} else {
|
} else {
|
||||||
Pair(filteredEvents[range.startIndex]!!.displayIndex, Timeline.Direction.BACKWARDS)
|
Pair(results[range.startIndex]!!.displayIndex, Timeline.Direction.BACKWARDS)
|
||||||
}
|
}
|
||||||
val state = getState(direction)
|
val state = getState(direction)
|
||||||
if (state.isPaginating) {
|
if (state.isPaginating) {
|
||||||
|
@ -503,7 +503,7 @@ internal class DefaultTimeline(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
changeSet.changes.forEach { index ->
|
changeSet.changes.forEach { index ->
|
||||||
val eventEntity = filteredEvents[index]
|
val eventEntity = results[index]
|
||||||
eventEntity?.eventId?.let { eventId ->
|
eventEntity?.eventId?.let { eventId ->
|
||||||
postSnapshot = rebuildEvent(eventId) {
|
postSnapshot = rebuildEvent(eventId) {
|
||||||
buildTimelineEvent(eventEntity)
|
buildTimelineEvent(eventEntity)
|
||||||
|
|
|
@ -167,7 +167,6 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
|
||||||
|
|
||||||
private fun handleReachEnd(realm: Realm, roomId: String, direction: PaginationDirection, currentChunk: ChunkEntity) {
|
private fun handleReachEnd(realm: Realm, roomId: String, direction: PaginationDirection, currentChunk: ChunkEntity) {
|
||||||
Timber.v("Reach end of $roomId")
|
Timber.v("Reach end of $roomId")
|
||||||
roomId.isBlank()
|
|
||||||
if (direction == PaginationDirection.FORWARDS) {
|
if (direction == PaginationDirection.FORWARDS) {
|
||||||
val currentLiveChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
|
val currentLiveChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
|
||||||
if (currentChunk != currentLiveChunk) {
|
if (currentChunk != currentLiveChunk) {
|
||||||
|
|
|
@ -395,4 +395,4 @@ class EllipsizingTextView @JvmOverloads constructor(context: Context, attrs: Att
|
||||||
val ellipsizeColor = Color.argb(ELLIPSIZE_ALPHA, Color.red(currentTextColor), Color.green(currentTextColor), Color.blue(currentTextColor))
|
val ellipsizeColor = Color.argb(ELLIPSIZE_ALPHA, Color.red(currentTextColor), Color.green(currentTextColor), Color.blue(currentTextColor))
|
||||||
ELLIPSIS.setSpan(ForegroundColorSpan(ellipsizeColor), 0, ELLIPSIS.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
ELLIPSIS.setSpan(ForegroundColorSpan(ellipsizeColor), 0, ELLIPSIS.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -350,9 +350,11 @@ class RoomDetailFragment @Inject constructor(
|
||||||
roomDetailViewModel.handle(RoomDetailAction.ExitTrackingUnreadMessagesState)
|
roomDetailViewModel.handle(RoomDetailAction.ExitTrackingUnreadMessagesState)
|
||||||
jumpToBottomView.visibility = View.INVISIBLE
|
jumpToBottomView.visibility = View.INVISIBLE
|
||||||
if (!roomDetailViewModel.timeline.isLive) {
|
if (!roomDetailViewModel.timeline.isLive) {
|
||||||
|
scrollOnNewMessageCallback.forceScrollOnNextUpdate()
|
||||||
roomDetailViewModel.timeline.restartWithEventId(null)
|
roomDetailViewModel.timeline.restartWithEventId(null)
|
||||||
|
} else {
|
||||||
|
layoutManager.scrollToPosition(0)
|
||||||
}
|
}
|
||||||
layoutManager.scrollToPosition(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jumpToBottomViewVisibilityManager = JumpToBottomViewVisibilityManager(
|
jumpToBottomViewVisibilityManager = JumpToBottomViewVisibilityManager(
|
||||||
|
|
|
@ -27,12 +27,22 @@ class ScrollOnNewMessageCallback(private val layoutManager: LinearLayoutManager,
|
||||||
private val timelineEventController: TimelineEventController) : DefaultListUpdateCallback {
|
private val timelineEventController: TimelineEventController) : DefaultListUpdateCallback {
|
||||||
|
|
||||||
private val newTimelineEventIds = CopyOnWriteArrayList<String>()
|
private val newTimelineEventIds = CopyOnWriteArrayList<String>()
|
||||||
|
private var forceScroll = false
|
||||||
|
|
||||||
fun addNewTimelineEventIds(eventIds: List<String>) {
|
fun addNewTimelineEventIds(eventIds: List<String>) {
|
||||||
newTimelineEventIds.addAll(0, eventIds)
|
newTimelineEventIds.addAll(0, eventIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun forceScrollOnNextUpdate() {
|
||||||
|
forceScroll = true
|
||||||
|
}
|
||||||
|
|
||||||
override fun onInserted(position: Int, count: Int) {
|
override fun onInserted(position: Int, count: Int) {
|
||||||
|
if (forceScroll) {
|
||||||
|
forceScroll = false
|
||||||
|
layoutManager.scrollToPosition(position)
|
||||||
|
return
|
||||||
|
}
|
||||||
Timber.v("On inserted $count count at position: $position")
|
Timber.v("On inserted $count count at position: $position")
|
||||||
if (layoutManager.findFirstVisibleItemPosition() != position) {
|
if (layoutManager.findFirstVisibleItemPosition() != position) {
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in a new issue