fediverse:creator in link cards (AND-182)

This commit is contained in:
Grishka
2024-06-15 00:32:56 +03:00
parent 264f9a933c
commit 115a6378d3
9 changed files with 270 additions and 74 deletions

View File

@@ -36,6 +36,7 @@ public class Card extends BaseModel{
public String blurhash;
public List<History> history;
public Instant publishedAt;
public Account authorAccount;
public transient Drawable blurhashPlaceholder;
@@ -49,6 +50,8 @@ public class Card extends BaseModel{
if(placeholder!=null)
blurhashPlaceholder=new BlurHashDrawable(placeholder, width, height);
}
if(authorAccount!=null)
authorAccount.postprocess();
}
@Override

View File

@@ -5,30 +5,41 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.model.Card;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.drawables.BlurhashCrossfadeDrawable;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.parceler.Parcels;
import java.util.Objects;
import me.grishka.appkit.Nav;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
import me.grishka.appkit.utils.V;
public class LinkCardStatusDisplayItem extends StatusDisplayItem{
private final Status status;
private final UrlImageLoaderRequest imgRequest;
private final UrlImageLoaderRequest imgRequest, authorAvaRequest;
private final SpannableStringBuilder parsedAuthorName;
private final CustomEmojiHelper authorNameEmojiHelper=new CustomEmojiHelper();
public LinkCardStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Status status){
super(parentID, parentFragment);
@@ -37,6 +48,17 @@ public class LinkCardStatusDisplayItem extends StatusDisplayItem{
imgRequest=new UrlImageLoaderRequest(status.card.image, 1000, 1000);
else
imgRequest=null;
if(status.card.authorAccount!=null){
parsedAuthorName=new SpannableStringBuilder(status.card.authorAccount.displayName);
if(AccountSessionManager.get(parentFragment.getAccountID()).getLocalPreferences().customEmojiInNames)
HtmlParser.parseCustomEmoji(parsedAuthorName, status.card.authorAccount.emojis);
authorNameEmojiHelper.setText(parsedAuthorName);
authorAvaRequest=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? status.card.authorAccount.avatar : status.card.authorAccount.avatarStatic, V.dp(50), V.dp(50));
}else{
parsedAuthorName=null;
authorAvaRequest=null;
}
}
@Override
@@ -46,21 +68,26 @@ public class LinkCardStatusDisplayItem extends StatusDisplayItem{
@Override
public int getImageCount(){
return imgRequest==null ? 0 : 1;
return 1+(status.card.authorAccount!=null ? (1+authorNameEmojiHelper.getImageCount()) : 0);
}
@Override
public ImageLoaderRequest getImageRequest(int index){
return imgRequest;
return switch(index){
case 0 -> imgRequest;
case 1 -> authorAvaRequest;
default -> authorNameEmojiHelper.getImageRequest(index-2);
};
}
public static class Holder extends StatusDisplayItem.Holder<LinkCardStatusDisplayItem> implements ImageLoaderViewHolder{
private final TextView title, description, domain, timestamp;
private final ImageView photo;
private final TextView title, description, domain, timestamp, authorBefore, authorAfter, authorName;
private final ImageView photo, authorAva;
private BlurhashCrossfadeDrawable crossfadeDrawable=new BlurhashCrossfadeDrawable();
private boolean didClear;
private final View inner;
private final View inner, authorFooter, authorChip;
private final boolean isLarge;
private final Drawable logoIcon;
public Holder(Context context, ViewGroup parent, boolean isLarge){
super(context, isLarge ? R.layout.display_item_link_card : R.layout.display_item_link_card_compact, parent);
@@ -71,9 +98,26 @@ public class LinkCardStatusDisplayItem extends StatusDisplayItem{
timestamp=findViewById(R.id.timestamp);
photo=findViewById(R.id.photo);
inner=findViewById(R.id.inner);
authorBefore=findViewById(R.id.author_before);
authorAfter=findViewById(R.id.author_after);
authorName=findViewById(R.id.author_name);
authorAva=findViewById(R.id.author_ava);
authorChip=findViewById(R.id.author_chip);
authorFooter=findViewById(R.id.author_footer);
inner.setOnClickListener(this::onClick);
inner.setOutlineProvider(OutlineProviders.roundedRect(12));
inner.setOutlineProvider(OutlineProviders.roundedRect(8));
inner.setClipToOutline(true);
if(!isLarge){
photo.setOutlineProvider(OutlineProviders.roundedRect(4));
photo.setClipToOutline(true);
}
authorAva.setOutlineProvider(OutlineProviders.roundedRect(3));
authorAva.setClipToOutline(true);
authorChip.setOnClickListener(this::onAuthorChipClick);
logoIcon=context.getResources().getDrawable(R.drawable.ic_ntf_logo, context.getTheme()).mutate();
logoIcon.setBounds(0, 0, V.dp(17), V.dp(17));
}
@SuppressLint("SetTextI18n")
@@ -86,11 +130,36 @@ public class LinkCardStatusDisplayItem extends StatusDisplayItem{
description.setVisibility(TextUtils.isEmpty(card.description) ? View.GONE : View.VISIBLE);
}
String cardDomain=HtmlParser.normalizeDomain(Objects.requireNonNull(Uri.parse(card.url).getHost()));
if(isLarge && !TextUtils.isEmpty(card.authorName)){
domain.setText(itemView.getContext().getString(R.string.article_by_author, card.authorName)+" · "+cardDomain);
domain.setText(TextUtils.isEmpty(card.providerName) ? cardDomain : card.providerName);
if(card.authorAccount!=null){
authorFooter.setVisibility(View.VISIBLE);
authorChip.setVisibility(View.VISIBLE);
authorBefore.setVisibility(View.VISIBLE);
String[] authorParts=itemView.getContext().getString(R.string.article_by_author, "{author}").split("\\{author\\}");
String before=authorParts[0].trim();
String after=authorParts.length>1 ? authorParts[1].trim() : "";
if(!TextUtils.isEmpty(before)){
authorBefore.setText(before);
}
if(TextUtils.isEmpty(after)){
authorAfter.setVisibility(View.GONE);
}else{
authorAfter.setVisibility(View.VISIBLE);
authorAfter.setText(after);
}
authorName.setText(item.parsedAuthorName);
authorBefore.setCompoundDrawablesRelative(logoIcon, null, null, null);
}else if(!TextUtils.isEmpty(card.authorName)){
authorFooter.setVisibility(View.VISIBLE);
authorBefore.setVisibility(View.VISIBLE);
authorBefore.setCompoundDrawables(null, null, null, null);
authorChip.setVisibility(View.GONE);
authorAfter.setVisibility(View.GONE);
authorBefore.setText(itemView.getContext().getString(R.string.article_by_author, card.authorName));
}else{
domain.setText(cardDomain);
authorFooter.setVisibility(View.GONE);
}
if(card.publishedAt!=null){
timestamp.setVisibility(View.VISIBLE);
timestamp.setText(" · "+UiUtils.formatRelativeTimestamp(itemView.getContext(), card.publishedAt));
@@ -119,25 +188,43 @@ public class LinkCardStatusDisplayItem extends StatusDisplayItem{
@Override
public void setImage(int index, Drawable drawable){
crossfadeDrawable.setImageDrawable(drawable);
if(didClear)
crossfadeDrawable.animateAlpha(0f);
Card card=item.status.card;
// Make sure the image is not stretched if the server returned wrong dimensions
if(drawable!=null && (drawable.getIntrinsicWidth()!=card.width || drawable.getIntrinsicHeight()!=card.height)){
photo.setImageDrawable(null);
photo.setImageDrawable(crossfadeDrawable);
if(index==0){
crossfadeDrawable.setImageDrawable(drawable);
if(didClear)
crossfadeDrawable.animateAlpha(0f);
Card card=item.status.card;
// Make sure the image is not stretched if the server returned wrong dimensions
if(drawable!=null && (drawable.getIntrinsicWidth()!=card.width || drawable.getIntrinsicHeight()!=card.height)){
photo.setImageDrawable(null);
photo.setImageDrawable(crossfadeDrawable);
}
}else if(index==1){
authorAva.setImageDrawable(drawable);
}else{
item.authorNameEmojiHelper.setImageDrawable(index-2, drawable);
authorName.invalidate();
}
}
@Override
public void clearImage(int index){
crossfadeDrawable.setCrossfadeAlpha(1f);
didClear=true;
if(index==0){
crossfadeDrawable.setCrossfadeAlpha(1f);
didClear=true;
}else{
setImage(index, null);
}
}
private void onClick(View v){
UiUtils.openURL(itemView.getContext(), item.parentFragment.getAccountID(), item.status.card.url, item.status);
}
private void onAuthorChipClick(View v){
Bundle args=new Bundle();
args.putString("account", item.parentFragment.getAccountID());
args.putParcelable("profileAccount", Parcels.wrap(item.status.card.authorAccount));
Nav.go(item.parentFragment.getActivity(), ProfileFragment.class, args);
}
}
}