Skip to content
This repository has been archived by the owner on Oct 28, 2024. It is now read-only.

Commit

Permalink
feature: Display post that's being quoted on Akkoma (#927)
Browse files Browse the repository at this point in the history
* Displaying Akkoma quote status

* Dummy display items for quote posts

* Only remove quote-inline with RE:

* fix null reference (reply-to instead of quote status)

* fix text bottom padding in quote

* Postprocess status quote

* fix rounded bottom for quoted media

closes #929

---------

Co-authored-by: sk <[email protected]>
  • Loading branch information
Jacocococo and sk22 authored Nov 13, 2023
1 parent aa42873 commit a8dcb11
Show file tree
Hide file tree
Showing 19 changed files with 65 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.joinmastodon.android.ui.displayitems.WarningFilteredStatusDisplayItem;
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
import org.joinmastodon.android.ui.utils.InsetStatusItemDecoration;
import org.joinmastodon.android.ui.utils.MediaAttachmentViewController;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.utils.ProvidesAssistContent;
Expand Down Expand Up @@ -358,6 +359,7 @@ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newStat
}
});
list.addItemDecoration(new StatusListItemDecoration());
list.addItemDecoration(new InsetStatusItemDecoration(this));
((UsableRecyclerView)list).setSelectorBoundsProvider(new UsableRecyclerView.SelectorBoundsProvider(){
private Rect tmpRect=new Rect();
@Override
Expand Down Expand Up @@ -565,7 +567,8 @@ public void onError(ErrorResponse error){

public void onRevealSpoilerClick(SpoilerStatusDisplayItem.Holder holder){
Status status=holder.getItem().status;
toggleSpoiler(status, holder.getItemID());
boolean isForQuote=holder.getItem().isForQuote;
toggleSpoiler(status, isForQuote, holder.getItemID());
}

public void onVisibilityIconClick(HeaderStatusDisplayItem.Holder holder) {
Expand All @@ -587,15 +590,16 @@ public void onSensitiveRevealed(MediaGridStatusDisplayItem.Holder holder) {
else notifyItemChangedBefore(holder.getItem(), HeaderStatusDisplayItem.class);
}

protected void toggleSpoiler(Status status, String itemID){
protected void toggleSpoiler(Status status, boolean isForQuote, String itemID){
status.spoilerRevealed=!status.spoilerRevealed;
if (!status.spoilerRevealed && !AccountSessionManager.get(accountID).getLocalPreferences().revealCWs)
status.sensitiveRevealed = false;

SpoilerStatusDisplayItem.Holder spoiler=findHolderOfType(itemID, SpoilerStatusDisplayItem.Holder.class);
List<SpoilerStatusDisplayItem.Holder> spoilers=findAllHoldersOfType(itemID, SpoilerStatusDisplayItem.Holder.class);
SpoilerStatusDisplayItem.Holder spoiler=spoilers.size() > 1 && isForQuote ? spoilers.get(1) : spoilers.get(0);
if(spoiler!=null) spoiler.rebind();
else notifyItemChanged(itemID, SpoilerStatusDisplayItem.class);
SpoilerStatusDisplayItem spoilerItem=Objects.requireNonNull(findItemOfType(itemID, SpoilerStatusDisplayItem.class));
SpoilerStatusDisplayItem spoilerItem=Objects.requireNonNull(spoiler.getItem());

int index=displayItems.indexOf(spoilerItem);
if(status.spoilerRevealed){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ public void getOutline(View view, Outline outline){
String prefix = (GlobalUserPreferences.prefixReplies == ALWAYS
|| (GlobalUserPreferences.prefixReplies == TO_OTHERS && !ownID.equals(status.account.id)))
&& !status.spoilerText.startsWith("re: ") ? "re: " : "";
spoilerEdit.setText(prefix + replyTo.spoilerText);
spoilerEdit.setText(prefix + status.spoilerText);
spoilerBtn.setSelected(true);
}
if (status.language != null && !status.language.isEmpty()) setPostLanguage(status.language);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ public void onItemClick(String id){
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
list.addItemDecoration(new InsetStatusItemDecoration(this));
list.addItemDecoration(new RecyclerView.ItemDecoration(){
private Paint paint=new Paint();
private Rect tmpRect=new Rect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,6 @@ enum StatusEditChangeType{
return items;
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
list.addItemDecoration(new InsetStatusItemDecoration(this));
}

@Override
public boolean isItemEnabled(String id){
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
mainStatus=Parcels.unwrap(getArguments().getParcelable("status"));
Account inReplyToAccount=Parcels.unwrap(getArguments().getParcelable("inReplyToAccount"));
refreshing=contextInitiallyRendered=getArguments().getBoolean("refresh", false);
if(inReplyToAccount!=null)
knownAccounts.put(inReplyToAccount.id, inReplyToAccount);
data.add(mainStatus);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ public void postprocess() throws ObjectValidationException{
if(filtered!=null)
for(FilterResult fr:filtered)
fr.postprocess();
if(quote!=null)
quote.postprocess();

spoilerRevealed=!hasSpoiler();
if(!spoilerRevealed) sensitive=true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import me.grishka.appkit.utils.V;

public class AudioStatusDisplayItem extends StatusDisplayItem{
public final Status status;
public final Attachment attachment;
private final ImageLoaderRequest imageRequest;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
import me.grishka.appkit.views.UsableRecyclerView;

public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
public final Status status;
private final Drawable placeholder;
private final boolean hideEmpty, forAnnouncement, playGifs;
private final String accountID;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
import me.grishka.appkit.Nav;

public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
public final Status status;
public final String accountID;

private static final DateTimeFormatter TIME_FORMATTER=DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG, FormatStyle.SHORT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import me.grishka.appkit.utils.V;

public class FooterStatusDisplayItem extends StatusDisplayItem{
public final Status status;
private final String accountID;
public boolean hideCounts;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

public class GapStatusDisplayItem extends StatusDisplayItem{
public boolean loading;
private final Status status;

public GapStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, Status status){
super(parentID, parentFragment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
private String accountID;
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
private SpannableStringBuilder parsedName;
public final Status status;
public boolean hasVisibilityToggle;
boolean needBottomPadding;
private CharSequence extraText;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import me.grishka.appkit.utils.V;

public class LinkCardStatusDisplayItem extends StatusDisplayItem{
private final Status status;
private final UrlImageLoaderRequest imgRequest;

public LinkCardStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Status status){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
private final List<Attachment> attachments;
private final Map<String, Pair<String, String>> translatedAttachments = new HashMap<>();
private final ArrayList<ImageLoaderRequest> requests=new ArrayList<>();
public final Status status;
public String sensitiveTitle;

public MediaGridStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, PhotoLayoutHelper.TiledLayoutResult tiledLayout, List<Attachment> attachments, Status status){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
public boolean needBottomPadding;
ReblogOrReplyLineStatusDisplayItem extra;
CharSequence fullText;
Status status;

public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick, Status status) {
this(parentID, parentFragment, text, emojis, icon, visibility, handleClick, text, status);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;

public class SpoilerStatusDisplayItem extends StatusDisplayItem{
public final Status status;
public final ArrayList<StatusDisplayItem> contentItems=new ArrayList<>();
private final CharSequence parsedTitle;
private CharSequence translatedTitle;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,15 @@
public abstract class StatusDisplayItem{
public final String parentID;
public final BaseStatusListFragment<?> parentFragment;
public Status status;
public boolean inset;
public int index;
public boolean
hasDescendantNeighbor=false,
hasAncestoringNeighbor=false,
isMainStatus=true,
isDirectDescendant=false;
isDirectDescendant=false,
isForQuote=false;

public static final int FLAG_INSET=1;
public static final int FLAG_NO_FOOTER=1 << 1;
Expand All @@ -73,6 +75,7 @@ public abstract class StatusDisplayItem{
public static final int FLAG_NO_HEADER=1 << 4;
public static final int FLAG_NO_TRANSLATE=1 << 5;
public static final int FLAG_NO_EMOJI_REACTIONS=1 << 6;
public static final int FLAG_IS_FOR_QUOTE=1 << 7;

public void setAncestryInfo(
boolean hasDescendantNeighbor,
Expand Down Expand Up @@ -232,20 +235,21 @@ public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?>
if(statusForContent.hasSpoiler()){
if (AccountSessionManager.get(accountID).getLocalPreferences().revealCWs) statusForContent.spoilerRevealed = true;
SpoilerStatusDisplayItem spoilerItem=new SpoilerStatusDisplayItem(parentID, fragment, null, statusForContent, Type.SPOILER);
if((flags & FLAG_IS_FOR_QUOTE)!=0){
for(StatusDisplayItem item:spoilerItem.contentItems){
item.isForQuote=true;
}
}
items.add(spoilerItem);
contentItems=spoilerItem.contentItems;
}else{
contentItems=items;
}

if (statusForContent.quote != null) {
boolean hasQuoteInlineTag = statusForContent.content.contains("<span class=\"quote-inline\">");
if (!hasQuoteInlineTag) {
String quoteUrl = statusForContent.quote.url;
String quoteInline = String.format("<span class=\"quote-inline\">%sRE: <a href=\"%s\">%s</a></span>",
statusForContent.content.endsWith("</p>") ? "" : "<br/><br/>", quoteUrl, quoteUrl);
statusForContent.content += quoteInline;
}
if(statusForContent.quote!=null) {
int quoteInlineIndex=statusForContent.content.lastIndexOf("<span class=\"quote-inline\"><br/><br/>RE:");
if (quoteInlineIndex!=-1)
statusForContent.content=statusForContent.content.substring(0, quoteInlineIndex);
}

boolean hasSpoiler=!TextUtils.isEmpty(statusForContent.spoilerText);
Expand Down Expand Up @@ -287,15 +291,21 @@ else if(statusForContent.sensitive && AccountSessionManager.get(accountID).getLo
if(statusForContent.poll!=null){
buildPollItems(parentID, fragment, statusForContent.poll, status, contentItems);
}
if(statusForContent.card!=null && statusForContent.mediaAttachments.isEmpty()){
if(statusForContent.card!=null && statusForContent.mediaAttachments.isEmpty() && statusForContent.quote==null){
contentItems.add(new LinkCardStatusDisplayItem(parentID, fragment, statusForContent));
}
if(statusForContent.quote!=null && !(parentObject instanceof Notification)){
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));
}
if(contentItems!=items && statusForContent.spoilerRevealed){
items.addAll(contentItems);
}
AccountLocalPreferences lp=fragment.getLocalPrefs();
if((flags & FLAG_NO_EMOJI_REACTIONS)==0 && lp.emojiReactionsEnabled &&
(lp.showEmojiReactions!=ONLY_OPENED || fragment instanceof ThreadFragment)){
(lp.showEmojiReactions!=ONLY_OPENED || fragment instanceof ThreadFragment) &&
statusForContent.reactions!=null){
boolean isMainStatus=fragment instanceof ThreadFragment t && t.getMainStatus().id.equals(statusForContent.id);
boolean showAddButton=lp.showEmojiReactions==ALWAYS || isMainStatus;
items.add(new EmojiReactionsStatusDisplayItem(parentID, fragment, statusForContent, accountID, !showAddButton, false));
Expand All @@ -307,8 +317,9 @@ else if(statusForContent.sensitive && AccountSessionManager.get(accountID).getLo
items.add(footer);
}
boolean inset=(flags & FLAG_INSET)!=0;
boolean isForQuote=(flags & FLAG_IS_FOR_QUOTE)!=0;
// add inset dummy so last content item doesn't clip out of inset bounds
if((inset || footer==null) && (flags & FLAG_CHECKABLE)==0){
if((inset || footer==null) && (flags & FLAG_CHECKABLE)==0 && !isForQuote){
items.add(new DummyStatusDisplayItem(parentID, fragment));
// in case we ever need the dummy to display a margin for the media grid again:
// (i forgot why we apparently don't need this anymore)
Expand All @@ -320,12 +331,22 @@ else if(statusForContent.sensitive && AccountSessionManager.get(accountID).getLo
items.add(gap=new GapStatusDisplayItem(parentID, fragment, status));
int i=1;
for(StatusDisplayItem item:items){
item.inset=inset;
if(inset)
item.inset=true;
if(isForQuote){
item.status=statusForContent;
item.isForQuote=true;
}
item.index=i++;
}
if(items!=contentItems && !statusForContent.spoilerRevealed){
for(StatusDisplayItem item:contentItems){
item.inset=inset;
if(inset)
item.inset=true;
if(isForQuote){
item.status=statusForContent;
item.isForQuote=true;
}
item.index=i++;
}
}
Expand Down Expand Up @@ -375,12 +396,15 @@ public enum Type{
}

public static abstract class Holder<T extends StatusDisplayItem> extends BindableViewHolder<T> implements UsableRecyclerView.DisableableClickable{
private Context context;

public Holder(View itemView){
super(itemView);
}

public Holder(Context context, int layout, ViewGroup parent){
super(context, layout, parent);
this.context=context;
}

public String getItemID(){
Expand All @@ -389,6 +413,16 @@ public String getItemID(){

@Override
public void onClick(){
if(item.isForQuote){
item.status.filterRevealed=true;
Bundle args=new Bundle();
args.putString("account", item.parentFragment.getAccountID());
args.putParcelable("status", Parcels.wrap(item.status.clone()));
args.putBoolean("refresh", true);
Nav.go((Activity) context, ThreadFragment.class, args);
return;
}

item.parentFragment.onItemClick(item.parentID);
}

Expand Down Expand Up @@ -420,13 +454,13 @@ public Optional<StatusDisplayItem> getDisplayItemOffset(int offset){

public boolean isLastDisplayItemForStatus(){
return getNextVisibleDisplayItem()
.map(n->!n.parentID.equals(item.parentID))
.map(next->!next.parentID.equals(item.parentID) || item.inset && !next.inset)
.orElse(true);
}

@Override
public boolean isEnabled(){
return item.parentFragment.isItemEnabled(item.parentID);
return item.parentFragment.isItemEnabled(item.parentID) || item.isForQuote;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
public boolean textSelectable;
public boolean reduceTopPadding;
public boolean disableTranslate;
public final Status status;

public TextStatusDisplayItem(String parentID, CharSequence text, BaseStatusListFragment parentFragment, Status status, boolean disableTranslate){
super(parentID, parentFragment);
Expand Down Expand Up @@ -113,7 +112,7 @@ public void onBind(TextStatusDisplayItem item){
text.setText(item.text);
}
text.setTextIsSelectable(false);
if(item.textSelectable) itemView.post(() -> text.setTextIsSelectable(true));
if(item.textSelectable && !item.isForQuote) itemView.post(() -> text.setTextIsSelectable(true));
text.setInvalidateOnEveryFrame(false);
itemView.setClickable(false);
itemView.setPadding(itemView.getPaddingLeft(), item.reduceTopPadding ? V.dp(6) : V.dp(12), itemView.getPaddingRight(), itemView.getPaddingBottom());
Expand All @@ -124,8 +123,8 @@ public void onBind(TextStatusDisplayItem item){

StatusDisplayItem next=getNextVisibleDisplayItem().orElse(null);
if(next!=null && !next.parentID.equals(item.parentID)) next=null;
int bottomPadding=next instanceof FooterStatusDisplayItem ? V.dp(6)
: item.inset ? V.dp(12)
int bottomPadding=item.inset ? V.dp(12)
: next instanceof FooterStatusDisplayItem ? V.dp(6)
: (next instanceof EmojiReactionsStatusDisplayItem || next==null) ? 0
: V.dp(12);
itemView.setPadding(itemView.getPaddingLeft(), itemView.getPaddingTop(), itemView.getPaddingRight(), bottomPadding);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
public boolean loading;
public final Status status;
public List<StatusDisplayItem> filteredItems;
public LegacyFilter applyingFilter;

Expand Down

0 comments on commit a8dcb11

Please sign in to comment.