mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Fix some issues and make test passes
This commit is contained in:
parent
f454078c6b
commit
1728d31401
@ -241,6 +241,11 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
|
||||
|
||||
val bobEventsListener = object : Timeline.Listener {
|
||||
override fun onTimelineFailure(throwable: Throwable) {
|
||||
// noop
|
||||
}
|
||||
|
||||
override fun onNewTimelineEvents(eventIds: List<String>) {
|
||||
// noop
|
||||
}
|
||||
|
||||
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
|
||||
|
@ -20,15 +20,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.InstrumentedTest
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.internal.database.helper.add
|
||||
import im.vector.matrix.android.internal.database.helper.lastStateIndex
|
||||
import im.vector.matrix.android.api.session.room.send.SendState
|
||||
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.mapper.toEntity
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.SessionRealmModule
|
||||
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.createFakeMessageEvent
|
||||
import im.vector.matrix.android.session.room.timeline.RoomDataHelper.createFakeRoomMemberEvent
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.createObject
|
||||
@ -58,8 +58,11 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||
fun add_shouldAdd_whenNotAlreadyIncluded() {
|
||||
monarchy.runTransactionSync { realm ->
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -68,65 +71,23 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||
fun add_shouldNotAdd_whenAlreadyIncluded() {
|
||||
monarchy.runTransactionSync { realm ->
|
||||
val chunk: ChunkEntity = realm.createObject()
|
||||
val fakeEvent = createFakeMessageEvent()
|
||||
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
|
||||
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.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap())
|
||||
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
|
||||
fun merge_shouldAddEvents_whenMergingBackward() {
|
||||
monarchy.runTransactionSync { realm ->
|
||||
val chunk1: ChunkEntity = realm.createObject()
|
||||
val chunk2: ChunkEntity = realm.createObject()
|
||||
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
|
||||
chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
|
||||
chunk1.timelineEvents.size shouldEqual 60
|
||||
}
|
||||
}
|
||||
@ -140,9 +101,9 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||
val eventsForChunk2 = eventsForChunk1 + createFakeListOfEvents(10)
|
||||
chunk1.isLastForward = true
|
||||
chunk2.isLastForward = false
|
||||
chunk1.addAll("roomId", eventsForChunk1, PaginationDirection.FORWARDS)
|
||||
chunk2.addAll("roomId", eventsForChunk2, PaginationDirection.BACKWARDS)
|
||||
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
|
||||
chunk1.addAll(ROOM_ID, eventsForChunk1, PaginationDirection.FORWARDS)
|
||||
chunk2.addAll(ROOM_ID, eventsForChunk2, PaginationDirection.BACKWARDS)
|
||||
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
|
||||
chunk1.timelineEvents.size shouldEqual 40
|
||||
chunk1.isLastForward.shouldBeTrue()
|
||||
}
|
||||
@ -155,9 +116,9 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||
val chunk2: ChunkEntity = realm.createObject()
|
||||
val prevToken = "prev_token"
|
||||
chunk1.prevToken = prevToken
|
||||
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk1.merge("roomId", chunk2, PaginationDirection.FORWARDS)
|
||||
chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.FORWARDS)
|
||||
chunk1.prevToken shouldEqual prevToken
|
||||
}
|
||||
}
|
||||
@ -169,19 +130,25 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||
val chunk2: ChunkEntity = realm.createObject()
|
||||
val nextToken = "next_token"
|
||||
chunk1.nextToken = nextToken
|
||||
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
|
||||
chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
|
||||
chunk1.nextToken shouldEqual nextToken
|
||||
}
|
||||
}
|
||||
|
||||
private fun ChunkEntity.addAll(roomId: String,
|
||||
events: List<Event>,
|
||||
direction: PaginationDirection,
|
||||
stateIndexOffset: Int = 0) {
|
||||
direction: PaginationDirection) {
|
||||
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
|
||||
.forEach {
|
||||
if (timelineEvents.find(it.eventId) == null) {
|
||||
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)
|
||||
}
|
||||
addTimelineEventFromMerge(localRealm, it, direction)
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,7 +88,7 @@ internal fun ChunkEntity.addStateEvent(roomId: String, stateEvent: EventEntity,
|
||||
internal fun ChunkEntity.addTimelineEvent(roomId: String,
|
||||
eventEntity: EventEntity,
|
||||
direction: PaginationDirection,
|
||||
roomMemberContentsByUser: HashMap<String, RoomMemberContent?>) {
|
||||
roomMemberContentsByUser: Map<String, RoomMemberContent?>) {
|
||||
val eventId = eventEntity.eventId
|
||||
if (timelineEvents.find(eventId) != null) {
|
||||
return
|
||||
@ -130,28 +110,60 @@ internal fun ChunkEntity.addTimelineEvent(roomId: String,
|
||||
val roomMemberContent = roomMemberContentsByUser[senderId]
|
||||
this.senderAvatar = roomMemberContent?.avatarUrl
|
||||
this.senderName = roomMemberContent?.displayName
|
||||
if (roomMemberContent?.displayName != null) {
|
||||
val isHistoricalUnique = roomMemberContentsByUser.values.find {
|
||||
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
|
||||
}
|
||||
isUniqueDisplayName = if (roomMemberContent?.displayName != null) {
|
||||
computeIsUnique(realm, roomId, isLastForward, roomMemberContent, roomMemberContentsByUser)
|
||||
} else {
|
||||
isUniqueDisplayName = true
|
||||
true
|
||||
}
|
||||
}
|
||||
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 {
|
||||
val readReceiptsSummaryEntity = ReadReceiptsSummaryEntity.where(realm, eventEntity.eventId).findFirst()
|
||||
?: 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.homeserver.HomeServerPinger
|
||||
import im.vector.matrix.android.internal.util.BackgroundDetectionObserver
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.Collections
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
@ -120,7 +120,7 @@ internal class DefaultTimeline(
|
||||
if (!results.isLoaded || !results.isValid) {
|
||||
return@OrderedRealmCollectionChangeListener
|
||||
}
|
||||
handleUpdates(changeSet)
|
||||
handleUpdates(results, changeSet)
|
||||
}
|
||||
|
||||
private val relationsListener = OrderedRealmCollectionChangeListener<RealmResults<EventAnnotationsSummaryEntity>> { collection, changeSet ->
|
||||
@ -185,7 +185,7 @@ internal class DefaultTimeline(
|
||||
.filterEventsWithSettings()
|
||||
.findAll()
|
||||
handleInitialLoad()
|
||||
filteredEvents.addChangeListener(eventsChangeListener)
|
||||
nonFilteredEvents.addChangeListener(eventsChangeListener)
|
||||
|
||||
eventRelations = EventAnnotationsSummaryEntity.whereInRoom(realm, roomId)
|
||||
.findAllAsync()
|
||||
@ -215,8 +215,8 @@ internal class DefaultTimeline(
|
||||
if (this::eventRelations.isInitialized) {
|
||||
eventRelations.removeAllChangeListeners()
|
||||
}
|
||||
if (this::filteredEvents.isInitialized) {
|
||||
filteredEvents.removeAllChangeListeners()
|
||||
if (this::nonFilteredEvents.isInitialized) {
|
||||
nonFilteredEvents.removeAllChangeListeners()
|
||||
}
|
||||
if (settings.shouldHandleHiddenReadReceipts()) {
|
||||
hiddenReadReceipts.dispose()
|
||||
@ -452,7 +452,7 @@ internal class DefaultTimeline(
|
||||
var shouldFetchInitialEvent = false
|
||||
val currentInitialEventId = initialEventId
|
||||
val initialDisplayIndex = if (currentInitialEventId == null) {
|
||||
filteredEvents.firstOrNull()?.displayIndex
|
||||
nonFilteredEvents.firstOrNull()?.displayIndex
|
||||
} else {
|
||||
val initialEvent = nonFilteredEvents.where()
|
||||
.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
|
||||
*/
|
||||
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.deletionRanges.isNotEmpty()) {
|
||||
clearAllValues()
|
||||
@ -488,9 +488,9 @@ internal class DefaultTimeline(
|
||||
var postSnapshot = false
|
||||
changeSet.insertionRanges.forEach { range ->
|
||||
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 {
|
||||
Pair(filteredEvents[range.startIndex]!!.displayIndex, Timeline.Direction.BACKWARDS)
|
||||
Pair(results[range.startIndex]!!.displayIndex, Timeline.Direction.BACKWARDS)
|
||||
}
|
||||
val state = getState(direction)
|
||||
if (state.isPaginating) {
|
||||
@ -503,7 +503,7 @@ internal class DefaultTimeline(
|
||||
}
|
||||
}
|
||||
changeSet.changes.forEach { index ->
|
||||
val eventEntity = filteredEvents[index]
|
||||
val eventEntity = results[index]
|
||||
eventEntity?.eventId?.let { eventId ->
|
||||
postSnapshot = rebuildEvent(eventId) {
|
||||
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) {
|
||||
Timber.v("Reach end of $roomId")
|
||||
roomId.isBlank()
|
||||
if (direction == PaginationDirection.FORWARDS) {
|
||||
val currentLiveChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
|
||||
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))
|
||||
ELLIPSIS.setSpan(ForegroundColorSpan(ellipsizeColor), 0, ELLIPSIS.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -350,9 +350,11 @@ class RoomDetailFragment @Inject constructor(
|
||||
roomDetailViewModel.handle(RoomDetailAction.ExitTrackingUnreadMessagesState)
|
||||
jumpToBottomView.visibility = View.INVISIBLE
|
||||
if (!roomDetailViewModel.timeline.isLive) {
|
||||
scrollOnNewMessageCallback.forceScrollOnNextUpdate()
|
||||
roomDetailViewModel.timeline.restartWithEventId(null)
|
||||
} else {
|
||||
layoutManager.scrollToPosition(0)
|
||||
}
|
||||
layoutManager.scrollToPosition(0)
|
||||
}
|
||||
|
||||
jumpToBottomViewVisibilityManager = JumpToBottomViewVisibilityManager(
|
||||
|
@ -27,12 +27,22 @@ class ScrollOnNewMessageCallback(private val layoutManager: LinearLayoutManager,
|
||||
private val timelineEventController: TimelineEventController) : DefaultListUpdateCallback {
|
||||
|
||||
private val newTimelineEventIds = CopyOnWriteArrayList<String>()
|
||||
private var forceScroll = false
|
||||
|
||||
fun addNewTimelineEventIds(eventIds: List<String>) {
|
||||
newTimelineEventIds.addAll(0, eventIds)
|
||||
}
|
||||
|
||||
fun forceScrollOnNextUpdate() {
|
||||
forceScroll = true
|
||||
}
|
||||
|
||||
override fun onInserted(position: Int, count: Int) {
|
||||
if (forceScroll) {
|
||||
forceScroll = false
|
||||
layoutManager.scrollToPosition(position)
|
||||
return
|
||||
}
|
||||
Timber.v("On inserted $count count at position: $position")
|
||||
if (layoutManager.findFirstVisibleItemPosition() != position) {
|
||||
return
|
||||
|
Loading…
Reference in New Issue
Block a user