fix timeline jumping (#4471)

Two things changed here:

The check for `positionStart`only in `onItemRangeInserted` is not always
correct - we only want to jump up when something is inserted at the top,
if we already are at the top.

`enablePlaceholders = false` has unintended side effects - the
recyclerview adapter sometimes receives an "onItemRangeRemoved" followed
by an "onItemRangeInserted", instead of just "onItemRangeChanged".

Together they should make sure the timelines stay were they are.
This commit is contained in:
Konrad Pozniak 2024-05-31 13:41:22 +02:00 committed by GitHub
parent 83403ebb58
commit 0483440381
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 22 additions and 30 deletions

View File

@ -45,8 +45,7 @@ class AccountMediaViewModel @Inject constructor(
val media = Pager(
config = PagingConfig(
pageSize = LOAD_AT_ONCE,
prefetchDistance = LOAD_AT_ONCE * 2,
enablePlaceholders = false
prefetchDistance = LOAD_AT_ONCE * 2
),
pagingSourceFactory = {
AccountMediaPagingSource(

View File

@ -162,7 +162,8 @@ class ConversationsFragment :
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
if (positionStart == 0 && adapter.itemCount != itemCount) {
val firstPos = (binding.recyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
if (firstPos == 0 && positionStart == 0 && adapter.itemCount != itemCount) {
binding.recyclerView.post {
if (getView() != null) {
binding.recyclerView.scrollBy(0, Utils.dpToPx(requireContext(), -30))

View File

@ -45,8 +45,7 @@ class ConversationsViewModel @Inject constructor(
@OptIn(ExperimentalPagingApi::class)
val conversationFlow = Pager(
config = PagingConfig(
pageSize = 30,
enablePlaceholders = false
pageSize = 30
),
remoteMediator = ConversationsRemoteMediator(api, database, accountManager),
pagingSourceFactory = {

View File

@ -41,8 +41,7 @@ class DomainBlocksRepository @Inject constructor(
val domainPager = Pager(
config = PagingConfig(
pageSize = PAGE_SIZE,
initialLoadSize = PAGE_SIZE,
enablePlaceholders = false
initialLoadSize = PAGE_SIZE
),
remoteMediator = DomainBlocksRemoteMediator(api, this),
pagingSourceFactory = factory

View File

@ -40,8 +40,7 @@ class DraftsViewModel @Inject constructor(
val drafts = Pager(
config = PagingConfig(
pageSize = 20,
enablePlaceholders = false
pageSize = 20
),
pagingSourceFactory = {
database.draftDao().draftsPagingSource(

View File

@ -27,8 +27,7 @@ class FollowedTagsViewModel @Inject constructor(
@OptIn(ExperimentalPagingApi::class)
val pager = Pager(
config = PagingConfig(
pageSize = 100,
enablePlaceholders = false
pageSize = 100
),
remoteMediator = FollowedTagsRemoteMediator(api, this),
pagingSourceFactory = {

View File

@ -229,7 +229,8 @@ class NotificationsFragment :
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
if (positionStart == 0 && adapter.itemCount != itemCount) {
val firstPos = (binding.recyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
if (firstPos == 0 && positionStart == 0 && adapter.itemCount != itemCount) {
binding.recyclerView.post {
if (getView() != null) {
binding.recyclerView.scrollBy(

View File

@ -95,8 +95,7 @@ class NotificationsViewModel @Inject constructor(
val notifications = refreshTrigger.flatMapLatest {
Pager(
config = PagingConfig(
pageSize = LOAD_AT_ONCE,
enablePlaceholders = false
pageSize = LOAD_AT_ONCE
),
remoteMediator = remoteMediator,
pagingSourceFactory = {

View File

@ -79,8 +79,7 @@ class ReportViewModel @Inject constructor(
initialKey = statusId,
config = PagingConfig(
pageSize = 20,
initialLoadSize = 20,
enablePlaceholders = false
initialLoadSize = 20
),
pagingSourceFactory = { StatusesPagingSource(accountId, mastodonApi) }
).flow

View File

@ -40,8 +40,7 @@ class ScheduledStatusViewModel @Inject constructor(
val data = Pager(
config = PagingConfig(
pageSize = 20,
initialLoadSize = 20,
enablePlaceholders = false
initialLoadSize = 20
),
pagingSourceFactory = pagingSourceFactory
).flow

View File

@ -90,8 +90,7 @@ class SearchViewModel @Inject constructor(
val statusesFlow = Pager(
config = PagingConfig(
pageSize = DEFAULT_LOAD_SIZE,
initialLoadSize = DEFAULT_LOAD_SIZE,
enablePlaceholders = false
initialLoadSize = DEFAULT_LOAD_SIZE
),
pagingSourceFactory = statusesPagingSourceFactory
).flow
@ -100,8 +99,7 @@ class SearchViewModel @Inject constructor(
val accountsFlow = Pager(
config = PagingConfig(
pageSize = DEFAULT_LOAD_SIZE,
initialLoadSize = DEFAULT_LOAD_SIZE,
enablePlaceholders = false
initialLoadSize = DEFAULT_LOAD_SIZE
),
pagingSourceFactory = accountsPagingSourceFactory
).flow
@ -110,8 +108,7 @@ class SearchViewModel @Inject constructor(
val hashtagsFlow = Pager(
config = PagingConfig(
pageSize = DEFAULT_LOAD_SIZE,
initialLoadSize = DEFAULT_LOAD_SIZE,
enablePlaceholders = false
initialLoadSize = DEFAULT_LOAD_SIZE
),
pagingSourceFactory = hashtagsPagingSourceFactory
).flow

View File

@ -252,7 +252,8 @@ class TimelineFragment :
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
if (positionStart == 0 && adapter.itemCount != itemCount) {
val firstPos = (binding.recyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
if (firstPos == 0 && positionStart == 0 && adapter.itemCount != itemCount) {
binding.recyclerView.post {
if (getView() != null) {
if (isSwipeToRefreshEnabled) {

View File

@ -86,8 +86,7 @@ class CachedTimelineViewModel @Inject constructor(
@OptIn(ExperimentalPagingApi::class)
override val statuses = Pager(
config = PagingConfig(
pageSize = LOAD_AT_ONCE,
enablePlaceholders = false
pageSize = LOAD_AT_ONCE
),
remoteMediator = CachedTimelineRemoteMediator(accountManager, api, db),
pagingSourceFactory = {

View File

@ -88,8 +88,7 @@ class NetworkTimelineViewModel @Inject constructor(
@OptIn(ExperimentalPagingApi::class)
override val statuses = Pager(
config = PagingConfig(
pageSize = LOAD_AT_ONCE,
enablePlaceholders = false
pageSize = LOAD_AT_ONCE
),
pagingSourceFactory = {
NetworkTimelinePagingSource(

View File

@ -26,6 +26,7 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SimpleItemAnimator
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
@ -76,7 +77,8 @@ class TrendingTagsFragment :
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
if (positionStart == 0 && adapter.itemCount != itemCount) {
val firstPos = (binding.recyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
if (firstPos == 0 && positionStart == 0 && adapter.itemCount != itemCount) {
binding.recyclerView.post {
if (getView() != null) {
binding.recyclerView.scrollBy(