hopefully unfuck removing statuses and reblogs

This commit is contained in:
sk
2023-10-19 21:42:17 +02:00
parent 95fa547f15
commit 387b31193f
4 changed files with 65 additions and 40 deletions

View File

@@ -9,6 +9,7 @@ import com.squareup.otto.Subscribe;
import org.joinmastodon.android.E; import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.CacheController;
import org.joinmastodon.android.api.session.AccountLocalPreferences; import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent; import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
@@ -31,6 +32,10 @@ import org.parceler.Parcels;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -176,56 +181,71 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
} }
} }
private void iterateRemoveStatus(List<Status> l, String id){ private boolean removeStatusDisplayItems(String parentID, int firstIndex, int ancestorFirstIndex, int ancestorLastIndex){
Iterator<Status> it=l.iterator();
while(it.hasNext()){
if(it.next().getContentStatus().id.equals(id)){
it.remove();
}
}
}
private void removeStatusDisplayItems(Status status, int index, int ancestorFirstIndex, int ancestorLastIndex, boolean deleteContent){
// did we find an ancestor that is also the status' neighbor? // did we find an ancestor that is also the status' neighbor?
if(ancestorFirstIndex>=0 && ancestorLastIndex==index-1){ if(ancestorFirstIndex>=0 && ancestorLastIndex==firstIndex-1){
for(int i=ancestorFirstIndex; i<=ancestorLastIndex; i++){ // update ancestor to have no descendant anymore
StatusDisplayItem item=displayItems.get(i); displayItems.subList(ancestorFirstIndex, ancestorLastIndex+1).forEach(i->i.hasDescendantNeighbor=false);
String id=deleteContent ? item.getContentID() : item.parentID;
// update ancestor to have no descendant anymore
if(id.equals(status.inReplyToId)) item.hasDescendantNeighbor=false;
}
adapter.notifyItemRangeChanged(ancestorFirstIndex, ancestorLastIndex-ancestorFirstIndex+1); adapter.notifyItemRangeChanged(ancestorFirstIndex, ancestorLastIndex-ancestorFirstIndex+1);
} }
if(index==-1) return; if(firstIndex==-1) return false;
int lastIndex; int lastIndex=firstIndex;
for(lastIndex=index;lastIndex<displayItems.size();lastIndex++){ while(lastIndex<displayItems.size()){
StatusDisplayItem item=displayItems.get(lastIndex); if(!displayItems.get(lastIndex).parentID.equals(parentID)) break;
String id=deleteContent ? item.getContentID() : item.parentID; lastIndex++;
if(!id.equals(status.id)) break;
} }
displayItems.subList(index, lastIndex).clear(); int count=lastIndex-firstIndex;
adapter.notifyItemRangeRemoved(index, lastIndex-index); displayItems.subList(firstIndex, lastIndex).clear();
adapter.notifyItemRangeRemoved(firstIndex, count);
return true;
} }
protected void removeStatus(Status status){ protected void removeStatus(Status status){
boolean deleteContent=status==status.getContentStatus(); final AccountSessionManager asm=AccountSessionManager.getInstance();
final CacheController cache=AccountSessionManager.get(accountID).getCacheController();
final boolean unReblogging=status.reblog!=null && asm.isSelf(accountID, status.account);
final Predicate<Status> isToBeRemovedReblog=item->item!=null && item.reblog!=null
&& item.reblog.id.equals(status.reblog.id)
&& asm.isSelf(accountID, item.account);
final BiPredicate<String, Supplier<String>> isToBeRemovedContent=(parentId, contentIdSupplier)->
parentId.equals(status.id) || contentIdSupplier.get().equals(status.id);
int ancestorFirstIndex=-1, ancestorLastIndex=-1; int ancestorFirstIndex=-1, ancestorLastIndex=-1;
for(int i=0;i<displayItems.size();i++){ for(int i=0;i<displayItems.size();i++){
StatusDisplayItem item=displayItems.get(i); StatusDisplayItem item=displayItems.get(i);
String id=deleteContent ? item.getContentID() : item.parentID; // we found a status that the to-be-removed status replies to!
if(id.equals(status.id)){ // storing indices to maybe update its display items
removeStatusDisplayItems(status, i, ancestorFirstIndex, ancestorLastIndex, deleteContent); if(item.parentID.equals(status.inReplyToId)){
ancestorFirstIndex=ancestorLastIndex=-1;
continue;
}
if(id.equals(status.inReplyToId)){
if(ancestorFirstIndex==-1) ancestorFirstIndex=i; if(ancestorFirstIndex==-1) ancestorFirstIndex=i;
ancestorLastIndex=i; ancestorLastIndex=i;
} }
// if we're un-reblogging, we compare the reblogged status's id with the current status's
if(unReblogging
? isToBeRemovedReblog.test(getStatusByID(item.parentID))
: isToBeRemovedContent.test(item.parentID, item::getContentStatusID)){
// if statuses are removed from index i, the next iteration should be on the same index again
if(removeStatusDisplayItems(item.parentID, i, ancestorFirstIndex, ancestorLastIndex)) i--;
// resetting in case we find another occurrence of the same status that also has ancestors
// (we won't - unless the timeline is being especially weird)
ancestorFirstIndex=-1; ancestorLastIndex=-1;
}
} }
iterateRemoveStatus(data, status.id);
iterateRemoveStatus(preloadedData, status.id); Consumer<List<Status>> removeStatusFromData=(list)->{
Iterator<Status> it=list.iterator();
while(it.hasNext()){
Status s=it.next();
if(unReblogging
? isToBeRemovedReblog.test(s)
: isToBeRemovedContent.test(s.id, s::getContentStatusID)){
it.remove();
cache.deleteStatus(s.id);
}
}
};
removeStatusFromData.accept(data);
removeStatusFromData.accept(preloadedData);
} }
@Override @Override
@@ -296,10 +316,14 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
@Subscribe @Subscribe
public void onReblogDeleted(ReblogDeletedEvent ev){ public void onReblogDeleted(ReblogDeletedEvent ev){
AccountSessionManager asm=AccountSessionManager.getInstance();
if(!ev.accountID.equals(accountID)) if(!ev.accountID.equals(accountID))
return; return;
for(Status item : data){ for(Status item : data){
if(item.getContentStatus().id.equals(ev.statusID) && item.reblog!=null){ boolean itemIsOwnReblog=item.reblog!=null
&& item.getContentStatusID().equals(ev.statusID)
&& asm.isSelf(accountID, item.account);
if(itemIsOwnReblog){
removeStatus(item); removeStatus(item);
break; break;
} }

View File

@@ -195,6 +195,10 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
return reblog!=null ? reblog : this; return reblog!=null ? reblog : this;
} }
public String getContentStatusID(){
return getContentStatus().id;
}
public String getStrippedText(){ public String getStrippedText(){
if(strippedText==null) if(strippedText==null)
strippedText=HtmlParser.strip(content); strippedText=HtmlParser.strip(content);

View File

@@ -89,7 +89,7 @@ public abstract class StatusDisplayItem{
} }
@NonNull @NonNull
public String getContentID(){ public String getContentStatusID(){
if(parentFragment instanceof StatusListFragment slf){ if(parentFragment instanceof StatusListFragment slf){
Status s=slf.getContentStatusByID(parentID); Status s=slf.getContentStatusByID(parentID);
return s!=null ? s.id : parentID; return s!=null ? s.id : parentID;

View File

@@ -638,11 +638,8 @@ public class UiUtils {
@Override @Override
public void onSuccess(Status result) { public void onSuccess(Status result) {
resultCallback.accept(result); resultCallback.accept(result);
CacheController cache=AccountSessionManager.get(accountID).getCacheController();
cache.deleteStatus(s.id);
E.post(new StatusDeletedEvent(s.id, accountID)); E.post(new StatusDeletedEvent(s.id, accountID));
if(status!=s){ if(status!=s){
cache.deleteStatus(status.id);
E.post(new StatusDeletedEvent(status.id, accountID)); E.post(new StatusDeletedEvent(status.id, accountID));
} }
} }