From ad04433944a40cc8b9c02616a036e1c6658c9ba7 Mon Sep 17 00:00:00 2001 From: Grishka Date: Sat, 26 Oct 2024 06:45:01 +0300 Subject: [PATCH] Load timeline gaps depending on scroll direction (AND-190) Closes #70, closes #154, closes #147, closes #281 --- .../fragments/HomeTimelineFragment.java | 105 ++++++++++++++++-- .../ui/displayitems/GapStatusDisplayItem.java | 2 + 2 files changed, 99 insertions(+), 8 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java index 08d52ead..7a2e25ca 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java @@ -73,6 +73,7 @@ import java.util.Locale; import java.util.Set; import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import me.grishka.appkit.Nav; import me.grishka.appkit.api.Callback; @@ -274,11 +275,35 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD newPostsBtnWrap.setOnHideButtonListener(this::hideNewPostsButton); updateToolbarLogo(); list.addOnScrollListener(new RecyclerView.OnScrollListener(){ + private HashSet gaps=new HashSet<>(); + @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){ if(newPostsBtnShown && list.getChildAdapterPosition(list.getChildAt(0))<=getMainAdapterOffset()){ hideNewPostsButton(); } + for(StatusDisplayItem item:displayItems){ + if(item instanceof GapStatusDisplayItem gap){ + gaps.add(gap); + } + } + if(gaps.isEmpty()) + return; + for(int i=0;i(){ + boolean insertBelowGap=!gap.enteredFromTop; + String maxID, sinceID; + if(gap.enteredFromTop){ + maxID=item.getItemID(); + sinceID=null; + }else{ + maxID=null; + int gapPos=displayItems.indexOf(gap); + sinceID=displayItems.get(gapPos+1).parentID; + } + loadAdditionalPosts(maxID, null, 20, sinceID, new Callback<>(){ @Override public void onSuccess(List result){ @@ -449,9 +484,9 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD if(gapStatus!=null){ gapStatus.hasGapAfter=false; if(needCache) - AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(gapStatus), false); + AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(List.of(gapStatus), false); } - }else{ + }else if(insertBelowGap){ Set idsBelowGap=new HashSet<>(); boolean belowGap=false; int gapPostIndex=0; @@ -462,7 +497,7 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD belowGap=true; s.hasGapAfter=false; if(needCache) - AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(s), false); + AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(List.of(s), false); }else{ gapPostIndex++; } @@ -480,8 +515,8 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD } if(needCache) AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.HOME); - List targetList=displayItems.subList(gapPos, gapPos+1); - targetList.clear(); + List targetList=displayItems.subList(gapPos, gapPos+1); // Get a sub-list that contains the gap item + targetList.clear(); // remove the gap item List insertedPosts=data.subList(gapPostIndex+1, gapPostIndex+1); for(Status s:result){ if(idsBelowGap.contains(s.id)) @@ -498,6 +533,60 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD } if(needCache) AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(insertedPosts, false); + }else{ + Set idsAboveGap=new HashSet<>(); + int gapPostIndex=0; + Status gapPost=null; + for(Status s:data){ + if(s.id.equals(gap.parentID)){ + gapPost=s; + break; + }else{ + idsAboveGap.add(s.id); + gapPostIndex++; + } + } + if(gapPost==null) + return; + boolean needAdjustScroll=false; + int scrollTop=0; + for(int i=0;i targetList=displayItems.subList(gapPos+1, gapPos+1); + List insertedPosts=data.subList(gapPostIndex+1, gapPostIndex+1); + for(int i=result.size()-1;i>=0;i--){ + Status s=result.get(i); + if(idsAboveGap.contains(s.id)) + break; + targetList.addAll(0, buildDisplayItems(s)); + insertedPosts.add(0, s); + } + boolean gapRemoved=false; + if(insertedPosts.size()