From 6157d4942af2d5ba030e29e409cf3c64dc328514 Mon Sep 17 00:00:00 2001 From: FineFindus Date: Sat, 6 Jul 2024 11:07:43 +0200 Subject: [PATCH 1/5] refactor(StatusDisplayItem): compile patter outside of function --- .../android/ui/displayitems/StatusDisplayItem.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java index 0607ede1f..92e41b039 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java @@ -84,6 +84,9 @@ public abstract class StatusDisplayItem{ public static final int FLAG_IS_FOR_QUOTE=1 << 7; public static final int FLAG_NO_MEDIA_PREVIEW=1 << 8; + + private final static Pattern QUOTE_PATTERN=Pattern.compile("[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)"); + public void setAncestryInfo( boolean hasDescendantNeighbor, boolean hasAncestoringNeighbor, @@ -379,8 +382,7 @@ public abstract class StatusDisplayItem{ } // I actually forgot where I took this, but it works - Pattern pattern = Pattern.compile("[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)"); - Matcher matcher = pattern.matcher(statusForContent.getStrippedText()); + Matcher matcher = QUOTE_PATTERN.matcher(statusForContent.getStrippedText()); String lastUrl = null; while (matcher.find()) { From cdd9b0553f5e05506e24f64c766a1364576c5309 Mon Sep 17 00:00:00 2001 From: FineFindus Date: Sat, 6 Jul 2024 12:47:40 +0200 Subject: [PATCH 2/5] refactor(StatusDisplayItem): rebuild StatusItems with quote --- .../fragments/BaseStatusListFragment.java | 43 ++++--------- .../ui/displayitems/StatusDisplayItem.java | 60 +++++++++++-------- 2 files changed, 47 insertions(+), 56 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java index 77658b1c5..5cd0754aa 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java @@ -47,7 +47,6 @@ import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.HashtagStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem; -import org.joinmastodon.android.ui.displayitems.LinkCardStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.PollFooterStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.PollOptionStatusDisplayItem; @@ -707,38 +706,22 @@ public abstract class BaseStatusListFragment exten toggleSpoiler(status, isForQuote, holder.getItemID()); } - public void onAddQuoteToStatus(Status status, Status parentStatus) { - int cardIndex=-1; - int textIndex=-1; - int i=0; - for(StatusDisplayItem item:displayItems){ - if(item.parentID.equals(parentStatus.id)){ - if(item instanceof LinkCardStatusDisplayItem){ - cardIndex=i; - }else if(item instanceof TextStatusDisplayItem){ - textIndex=i; - } + public void updateStatusWithQuote(Status status) { + int startIndex=-1; + int endIndex=-1; + for(int i=0; i items=StatusDisplayItem.buildItems(this, status, accountID, parentStatus, knownAccounts, null, flags); - displayItems.remove(cardIndex); - adapter.notifyItemRemoved(cardIndex); - displayItems.addAll(cardIndex, items); - adapter.notifyItemRangeInserted(cardIndex, items.size()); - return; - } - - if (textIndex!=-1) { - ArrayList items=StatusDisplayItem.buildItems(this, status, accountID, parentStatus, knownAccounts, null, flags); - displayItems.addAll(textIndex+1, items); - adapter.notifyItemRangeInserted(textIndex+1, items.size()); + if (startIndex!=-1 && endIndex!=-1) { + ArrayList items=StatusDisplayItem.buildItems(this, status, accountID, status, knownAccounts, null, 0); + displayItems.subList(startIndex, endIndex+1).clear(); + displayItems.addAll(startIndex, items); + adapter.notifyItemRangeChanged(startIndex, items.size()); } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java index 92e41b039..b4682c4a6 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java @@ -48,6 +48,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.Predicate; import java.util.regex.Matcher; @@ -328,6 +329,8 @@ public abstract class StatusDisplayItem{ if(!statusForContent.mediaAttachments.isEmpty() && statusForContent.poll==null) // add spacing if immediately preceded by attachment contentItems.add(new DummyStatusDisplayItem(parentID, fragment)); contentItems.addAll(buildItems(fragment, statusForContent.quote, accountID, parentObject, knownAccounts, filterContext, FLAG_NO_FOOTER|FLAG_INSET|FLAG_NO_EMOJI_REACTIONS|FLAG_IS_FOR_QUOTE)); + } else { + tryAddNonOfficialQuote(statusForContent, fragment, accountID); } if(contentItems!=items && statusForContent.spoilerRevealed){ items.addAll(contentItems); @@ -381,32 +384,6 @@ public abstract class StatusDisplayItem{ } } - // I actually forgot where I took this, but it works - Matcher matcher = QUOTE_PATTERN.matcher(statusForContent.getStrippedText()); - - String lastUrl = null; - while (matcher.find()) { - lastUrl = matcher.group(0); - // The regex doesn't capture the scheme, so I add one here manually, so that the looksLikeFediverseUrlMethod actually works - lastUrl = "https://" + lastUrl; - } - - if (UiUtils.looksLikeFediverseUrl(lastUrl) && statusForContent.quote == null) { - new GetSearchResults(lastUrl, GetSearchResults.Type.STATUSES, true, null, 0, 0).setCallback(new Callback<>(){ - @Override - public void onSuccess(SearchResults results){ - if (!results.statuses.isEmpty()){ - fragment.onAddQuoteToStatus(results.statuses.get(0), statusForContent); - } - } - - @Override - public void onError(ErrorResponse error){ - // Nothing - } - }).exec(accountID); - } - List nonGapItems=gap!=null ? items.subList(0, items.size()-1) : items; WarningFilteredStatusDisplayItem warning=applyingFilter==null ? null : new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, nonGapItems, applyingFilter); @@ -429,6 +406,37 @@ public abstract class StatusDisplayItem{ items.add(new PollFooterStatusDisplayItem(parentID, fragment, poll, status)); } + /** + * Tries to adds a non-official quote to a status. + * A non-official quote is a quote on an instance that does not support quotes officially. + */ + private static void tryAddNonOfficialQuote(Status status, BaseStatusListFragment fragment, String accountID) { + Matcher matcher=QUOTE_PATTERN.matcher(status.getStrippedText()); + + String quoteURL=null; + while (matcher.find()) { + quoteURL=matcher.group(0); + } + quoteURL="https://"+quoteURL; + + if (UiUtils.looksLikeFediverseUrl(quoteURL)) { + new GetSearchResults(quoteURL, GetSearchResults.Type.STATUSES, true, null, 0, 0).setCallback(new Callback<>(){ + @Override + public void onSuccess(SearchResults results){ + if (!results.statuses.isEmpty()){ + status.quote=results.statuses.get(0); + fragment.updateStatusWithQuote(status); + } + } + + @Override + public void onError(ErrorResponse error){ + Log.w("StatusDisplayItem", "onError: failed to find quote status" +error); + } + }).exec(accountID); + } + } + public enum Type{ HEADER, REBLOG_OR_REPLY_LINE, From 5fd2e322f6caf8f6c9d00fd5871f82f6ba336c70 Mon Sep 17 00:00:00 2001 From: FineFindus Date: Sat, 6 Jul 2024 12:53:38 +0200 Subject: [PATCH 3/5] fix(StatusDisplayItem): don't display self-referential quotes --- .../android/ui/displayitems/StatusDisplayItem.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java index b4682c4a6..d0f703d60 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java @@ -424,8 +424,12 @@ public abstract class StatusDisplayItem{ @Override public void onSuccess(SearchResults results){ if (!results.statuses.isEmpty()){ - status.quote=results.statuses.get(0); - fragment.updateStatusWithQuote(status); + Status quote=results.statuses.get(0); + // don't show self-referential quotes + if(!Objects.equals(status.id, results.statuses.get(0).id)){ + status.quote=quote; + fragment.updateStatusWithQuote(status); + } } } From ff90e21e86fbbcfa22edf916ee116102d8b6c2b0 Mon Sep 17 00:00:00 2001 From: FineFindus Date: Sat, 6 Jul 2024 13:30:25 +0200 Subject: [PATCH 4/5] feat(StatusDisplayItem/Quote): hide non-official quote mentions Hides the URL, with optional 'RE:' prefix and whitespace, that is used to construct non-official quotes. --- .../android/ui/displayitems/StatusDisplayItem.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java index d0f703d60..38720e5c0 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java @@ -86,6 +86,7 @@ public abstract class StatusDisplayItem{ public static final int FLAG_NO_MEDIA_PREVIEW=1 << 8; + private final static Pattern QUOTE_MENTION_PATTERN=Pattern.compile("(?:

)?\\s?(?:RE:\\s?)?]*>https:\\/\\/<\\/span>[^<]+<\\/span>[^<]+<\\/span><\\/a>(?:<\\/p>)?$"); private final static Pattern QUOTE_PATTERN=Pattern.compile("[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)"); public void setAncestryInfo( @@ -274,6 +275,14 @@ public abstract class StatusDisplayItem{ int quoteInlineIndex=statusForContent.content.lastIndexOf("

RE:"); if(quoteInlineIndex!=-1) statusForContent.content=statusForContent.content.substring(0, quoteInlineIndex); + else { + // hide non-official quote patters + Matcher matcher=QUOTE_MENTION_PATTERN.matcher(status.content); + if(matcher.find()){ + String quoteMention=matcher.group(); + statusForContent.content=statusForContent.content.replace(quoteMention, ""); + } + } } boolean hasSpoiler=!TextUtils.isEmpty(statusForContent.spoilerText); From a67c8b36b16b24210e26f10f70122f86023adf9c Mon Sep 17 00:00:00 2001 From: FineFindus Date: Sat, 6 Jul 2024 13:35:14 +0200 Subject: [PATCH 5/5] refactor(StatusDisplayItem/quote): use regex to find last URL --- .../android/ui/displayitems/StatusDisplayItem.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java index 38720e5c0..804c9cfce 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java @@ -87,7 +87,7 @@ public abstract class StatusDisplayItem{ private final static Pattern QUOTE_MENTION_PATTERN=Pattern.compile("(?:

)?\\s?(?:RE:\\s?)?]*>https:\\/\\/<\\/span>[^<]+<\\/span>[^<]+<\\/span><\\/a>(?:<\\/p>)?$"); - private final static Pattern QUOTE_PATTERN=Pattern.compile("[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)"); + private final static Pattern QUOTE_PATTERN=Pattern.compile("[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)$"); public void setAncestryInfo( boolean hasDescendantNeighbor, @@ -422,11 +422,9 @@ public abstract class StatusDisplayItem{ private static void tryAddNonOfficialQuote(Status status, BaseStatusListFragment fragment, String accountID) { Matcher matcher=QUOTE_PATTERN.matcher(status.getStrippedText()); - String quoteURL=null; - while (matcher.find()) { - quoteURL=matcher.group(0); - } - quoteURL="https://"+quoteURL; + if(!matcher.find()) + return; + String quoteURL="https://"+matcher.group(); if (UiUtils.looksLikeFediverseUrl(quoteURL)) { new GetSearchResults(quoteURL, GetSearchResults.Type.STATUSES, true, null, 0, 0).setCallback(new Callback<>(){ @@ -444,7 +442,7 @@ public abstract class StatusDisplayItem{ @Override public void onError(ErrorResponse error){ - Log.w("StatusDisplayItem", "onError: failed to find quote status" +error); + Log.w("StatusDisplayItem", "onError: failed to find quote status with URL: " + quoteURL + " " + error); } }).exec(accountID); }