Merge remote-tracking branch 'megalodon_main/main'
# Conflicts: # mastodon/build.gradle
This commit is contained in:
@@ -121,7 +121,7 @@ public class CacheController{
|
||||
db.insertWithOnConflict("home_timeline", null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
||||
}
|
||||
if(!clear)
|
||||
db.delete("home_timeline", "`id` NOT IN (SELECT `id` FROM `home_timeline` ORDER BY `time` DESC LIMIT ?)", new String[]{"1000"});
|
||||
db.delete("home_timeline", "`id` NOT IN (SELECT `id` FROM `home_timeline` ORDER BY `time` DESC LIMIT ?)", new String[]{"100"});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -53,9 +53,7 @@ public class MastodonAPIController{
|
||||
.registerTypeAdapter(Status.class, new Status.StatusDeserializer())
|
||||
.create();
|
||||
private static WorkerThread thread=new WorkerThread("MastodonAPIController");
|
||||
private static OkHttpClient httpClient=new OkHttpClient.Builder()
|
||||
.readTimeout(5, TimeUnit.MINUTES)
|
||||
.build();
|
||||
private static OkHttpClient httpClient=new OkHttpClient.Builder().build();
|
||||
|
||||
private AccountSession session;
|
||||
private static List<String> badDomains = new ArrayList<>();
|
||||
@@ -113,13 +111,13 @@ public class MastodonAPIController{
|
||||
}
|
||||
|
||||
Request hreq=builder.build();
|
||||
Call call=httpClient.newCall(hreq);
|
||||
OkHttpClient client=req.timeout>0
|
||||
? httpClient.newBuilder().readTimeout(req.timeout, TimeUnit.MILLISECONDS).build()
|
||||
: httpClient;
|
||||
Call call=client.newCall(hreq);
|
||||
synchronized(req){
|
||||
req.okhttpCall=call;
|
||||
}
|
||||
if(req.timeout>0){
|
||||
call.timeout().timeout(req.timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
if(BuildConfig.DEBUG)
|
||||
Log.d(TAG, "["+(session==null ? "no-auth" : session.getID())+"] Sending request: "+hreq);
|
||||
|
||||
@@ -153,8 +153,9 @@ public abstract class MastodonAPIRequest<T> extends APIRequest<T>{
|
||||
headers.put(key, value);
|
||||
}
|
||||
|
||||
protected void setTimeout(long timeout){
|
||||
public MastodonAPIRequest<T> setTimeout(long timeout){
|
||||
this.timeout=timeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected String getPathPrefix(){
|
||||
|
||||
@@ -237,21 +237,25 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
||||
|
||||
ViewTreeObserver vto = getToolbar().getViewTreeObserver();
|
||||
if (vto.isAlive()) {
|
||||
vto.addOnGlobalLayoutListener(() -> {
|
||||
Toolbar t = getToolbar();
|
||||
if (t == null) return;
|
||||
int toolbarWidth = t.getWidth();
|
||||
if (toolbarWidth == 0) return;
|
||||
vto.addOnGlobalLayoutListener(()->{
|
||||
Toolbar t=getToolbar();
|
||||
if(t==null) return;
|
||||
int toolbarWidth=t.getWidth();
|
||||
if(toolbarWidth==0) return;
|
||||
|
||||
int toolbarFrameWidth = toolbarFrame.getWidth();
|
||||
int padding = toolbarWidth - toolbarFrameWidth;
|
||||
FrameLayout parent = ((FrameLayout) toolbarShowNewPostsBtn.getParent());
|
||||
if (padding == parent.getPaddingStart()) return;
|
||||
int toolbarFrameWidth=toolbarFrame.getWidth();
|
||||
int actionsWidth=toolbarWidth-toolbarFrameWidth;
|
||||
// margin (4) + padding (12) + icon (24) + margin (8) + chevron (16) + padding (12)
|
||||
int switcherWidth=V.dp(76);
|
||||
FrameLayout parent=((FrameLayout) toolbarShowNewPostsBtn.getParent());
|
||||
if(actionsWidth==parent.getPaddingStart()) return;
|
||||
int paddingMax=Math.max(actionsWidth, switcherWidth);
|
||||
int paddingEnd=(Math.max(0, switcherWidth-actionsWidth));
|
||||
|
||||
// toolbar frame goes from screen edge to beginning of right-aligned option buttons.
|
||||
// centering button by applying the same space on the left
|
||||
parent.setPaddingRelative(padding, 0, 0, 0);
|
||||
toolbarShowNewPostsBtn.setMaxWidth(toolbarWidth - padding * 2);
|
||||
parent.setPaddingRelative(paddingMax, 0, paddingEnd, 0);
|
||||
toolbarShowNewPostsBtn.setMaxWidth(toolbarWidth-paddingMax*2);
|
||||
|
||||
switcher.setPivotX(V.dp(28)); // padding + half of icon
|
||||
switcher.setPivotY(switcher.getHeight() / 2f);
|
||||
|
||||
@@ -136,6 +136,7 @@ public class HomeTimelineFragment extends StatusListFragment {
|
||||
public void onSuccess(List<Status> result){
|
||||
currentRequest=null;
|
||||
dataLoading=false;
|
||||
refreshDone();
|
||||
if(result.isEmpty() || getActivity()==null)
|
||||
return;
|
||||
Status last=result.get(result.size()-1);
|
||||
@@ -157,7 +158,6 @@ public class HomeTimelineFragment extends StatusListFragment {
|
||||
prependItems(toAdd, true);
|
||||
if(parent != null && GlobalUserPreferences.showNewPostsButton) parent.showNewPostsButton();
|
||||
}
|
||||
refreshDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.squareup.otto.Subscribe;
|
||||
|
||||
import org.joinmastodon.android.E;
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
import org.joinmastodon.android.api.CacheController;
|
||||
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.events.StatusMuteChangedEvent;
|
||||
@@ -34,6 +35,10 @@ import org.parceler.Parcels;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
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.Stream;
|
||||
|
||||
@@ -193,56 +198,71 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
|
||||
}
|
||||
}
|
||||
|
||||
private void iterateRemoveStatus(List<Status> l, String id){
|
||||
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){
|
||||
private boolean removeStatusDisplayItems(String parentID, int firstIndex, int ancestorFirstIndex, int ancestorLastIndex){
|
||||
// did we find an ancestor that is also the status' neighbor?
|
||||
if(ancestorFirstIndex>=0 && ancestorLastIndex==index-1){
|
||||
for(int i=ancestorFirstIndex; i<=ancestorLastIndex; i++){
|
||||
StatusDisplayItem item=displayItems.get(i);
|
||||
String id=deleteContent ? item.getContentID() : item.parentID;
|
||||
// update ancestor to have no descendant anymore
|
||||
if(id.equals(status.inReplyToId)) item.hasDescendantNeighbor=false;
|
||||
}
|
||||
if(ancestorFirstIndex>=0 && ancestorLastIndex==firstIndex-1){
|
||||
// update ancestor to have no descendant anymore
|
||||
displayItems.subList(ancestorFirstIndex, ancestorLastIndex+1).forEach(i->i.hasDescendantNeighbor=false);
|
||||
adapter.notifyItemRangeChanged(ancestorFirstIndex, ancestorLastIndex-ancestorFirstIndex+1);
|
||||
}
|
||||
|
||||
if(index==-1) return;
|
||||
int lastIndex;
|
||||
for(lastIndex=index;lastIndex<displayItems.size();lastIndex++){
|
||||
StatusDisplayItem item=displayItems.get(lastIndex);
|
||||
String id=deleteContent ? item.getContentID() : item.parentID;
|
||||
if(!id.equals(status.id)) break;
|
||||
if(firstIndex==-1) return false;
|
||||
int lastIndex=firstIndex;
|
||||
while(lastIndex<displayItems.size()){
|
||||
if(!displayItems.get(lastIndex).parentID.equals(parentID)) break;
|
||||
lastIndex++;
|
||||
}
|
||||
displayItems.subList(index, lastIndex).clear();
|
||||
adapter.notifyItemRangeRemoved(index, lastIndex-index);
|
||||
int count=lastIndex-firstIndex;
|
||||
displayItems.subList(firstIndex, lastIndex).clear();
|
||||
adapter.notifyItemRangeRemoved(firstIndex, count);
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
for(int i=0;i<displayItems.size();i++){
|
||||
StatusDisplayItem item=displayItems.get(i);
|
||||
String id=deleteContent ? item.getContentID() : item.parentID;
|
||||
if(id.equals(status.id)){
|
||||
removeStatusDisplayItems(status, i, ancestorFirstIndex, ancestorLastIndex, deleteContent);
|
||||
ancestorFirstIndex=ancestorLastIndex=-1;
|
||||
continue;
|
||||
}
|
||||
if(id.equals(status.inReplyToId)){
|
||||
// we found a status that the to-be-removed status replies to!
|
||||
// storing indices to maybe update its display items
|
||||
if(item.parentID.equals(status.inReplyToId)){
|
||||
if(ancestorFirstIndex==-1) ancestorFirstIndex=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
|
||||
@@ -335,10 +355,14 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
|
||||
|
||||
@Subscribe
|
||||
public void onReblogDeleted(ReblogDeletedEvent ev){
|
||||
AccountSessionManager asm=AccountSessionManager.getInstance();
|
||||
if(!ev.accountID.equals(accountID))
|
||||
return;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.util.stream.Collectors;
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class SearchFragment extends BaseStatusListFragment<SearchResult>{
|
||||
@@ -142,7 +143,7 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
|
||||
}*/
|
||||
int offset=_offset;
|
||||
currentRequest=new GetSearchResults(currentQuery, type, type==null, maxID, offset, type==null ? 0 : count)
|
||||
.setCallback(new Callback<>(){
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(SearchResults result){
|
||||
ArrayList<SearchResult> results=new ArrayList<>();
|
||||
@@ -165,16 +166,8 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
|
||||
unfilteredResults=results;
|
||||
onDataLoaded(filterSearchResults(results), type!=null && !results.isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
currentRequest=null;
|
||||
Activity a=getActivity();
|
||||
if(a==null)
|
||||
return;
|
||||
error.showToast(a);
|
||||
}
|
||||
})
|
||||
.setTimeout(180000) // 3 minutes (searches can take a long time)
|
||||
.exec(accountID);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.imageloader.ViewImageLoader;
|
||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class ReportDoneFragment extends MastodonToolbarFragment{
|
||||
|
||||
@@ -242,7 +242,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
||||
|
||||
AlertDialog.Builder alert=new M3AlertDialogBuilder(getActivity())
|
||||
.setTitle(R.string.sk_settings_color_palette)
|
||||
.setSingleChoiceItems(items.toArray(String[]::new),
|
||||
.setSingleChoiceItems(items.stream().toArray(String[]::new),
|
||||
selected, (dlg, item)->newSelected[0]=item)
|
||||
.setPositiveButton(R.string.ok, (dlg, item)->save.accept(false))
|
||||
.setNegativeButton(R.string.cancel, null);
|
||||
|
||||
@@ -204,6 +204,10 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
|
||||
return reblog!=null ? reblog : this;
|
||||
}
|
||||
|
||||
public String getContentStatusID(){
|
||||
return getContentStatus().id;
|
||||
}
|
||||
|
||||
public String getStrippedText(){
|
||||
if(strippedText==null)
|
||||
strippedText=HtmlParser.strip(content);
|
||||
|
||||
@@ -92,7 +92,7 @@ public abstract class StatusDisplayItem{
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getContentID(){
|
||||
public String getContentStatusID(){
|
||||
if(parentFragment instanceof StatusListFragment slf){
|
||||
Status s=slf.getContentStatusByID(parentID);
|
||||
return s!=null ? s.id : parentID;
|
||||
|
||||
@@ -647,11 +647,8 @@ public class UiUtils {
|
||||
@Override
|
||||
public void onSuccess(Status result) {
|
||||
resultCallback.accept(result);
|
||||
CacheController cache=AccountSessionManager.get(accountID).getCacheController();
|
||||
cache.deleteStatus(s.id);
|
||||
E.post(new StatusDeletedEvent(s.id, accountID));
|
||||
if(status!=s){
|
||||
cache.deleteStatus(status.id);
|
||||
E.post(new StatusDeletedEvent(status.id, accountID));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user