Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: dispay inline avatar in thread replies #978

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
Expand All @@ -15,10 +16,14 @@
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.ui.text.AvatarSpan;
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.text.SpacerSpan;
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
import org.joinmastodon.android.ui.utils.UiUtils;

Expand All @@ -43,16 +48,32 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
public boolean needBottomPadding;
ReblogOrReplyLineStatusDisplayItem extra;
CharSequence fullText;
CharSequence boostingTimestamp;

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);
this(parentID, parentFragment, text, emojis, icon, visibility, handleClick, text, status, null);
}

public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick, CharSequence fullText, Status status) {
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick, CharSequence fullText, Status status, Account account) {
super(parentID, parentFragment);
SpannableStringBuilder ssb=new SpannableStringBuilder(text);
if(AccountSessionManager.get(parentFragment.getAccountID()).getLocalPreferences().customEmojiInNames)
HtmlParser.parseCustomEmoji(ssb, emojis);

if(status.reblog!=null&&handleClick!=null){
//add temp chars for span replacement, should be same as spans added below
ssb.insert(0, " ");
ssb.setSpan(new AvatarSpan(status.account), 0, 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
ssb.setSpan(new SpacerSpan(15, 20), 1, 2, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
}
int replyPrefixLength=context.getString(R.string.in_reply_to).length()-2; //subtract 2 for placeholder
if(status.inReplyToAccountId!=null&&ssb.length()>replyPrefixLength&&account!=null){
//add temp chars for span replacement, should be same as spans added below
ssb.insert(replyPrefixLength, " ");
ssb.setSpan(new SpacerSpan(15, 20), replyPrefixLength+1, replyPrefixLength+2, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
ssb.setSpan(new AvatarSpan(account), replyPrefixLength+1, replyPrefixLength+2, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
ssb.setSpan(new SpacerSpan(15, 20), replyPrefixLength+2, replyPrefixLength+3, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
}
this.text=ssb;
emojiHelper.setText(ssb);
this.fullText=fullText;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public static ReblogOrReplyLineStatusDisplayItem buildReplyLine(BaseStatusListFr
: fragment.getString(R.string.in_reply_to, account.getDisplayName());
return new ReblogOrReplyLineStatusDisplayItem(
parentID, fragment, text, account == null ? List.of() : account.emojis,
R.drawable.ic_fluent_arrow_reply_20sp_filled, null, null, fullText, status
R.drawable.ic_fluent_arrow_reply_20sp_filled, null, null, fullText, status, account
);
}

Expand Down Expand Up @@ -182,7 +182,7 @@ public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?>
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, text, status.account.emojis, R.drawable.ic_fluent_arrow_repeat_all_20sp_filled, isOwnPost ? status.visibility : null, i->{
args.putParcelable("profileAccount", Parcels.wrap(status.account));
Nav.go(fragment.getActivity(), ProfileFragment.class, args);
}, null, status));
}, null, status, status.account));
} else if (!(status.tags.isEmpty() ||
fragment instanceof HashtagTimelineFragment ||
fragment instanceof ListTimelineFragment
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.joinmastodon.android.ui.text;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.style.ReplacementSpan;

import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Emoji;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
import me.grishka.appkit.utils.V;

public class AvatarSpan extends CustomEmojiSpan{

public AvatarSpan(Account account){
//this is a hacky solution to allow loading of avatars in the middle of strings,
//using already existing code for loading emojis
super(new Emoji(account.avatarStatic, account.avatar, account.avatarStatic));
}

@Override
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint){
//modified draw of a CustomEmojiSpan, drawing a circular image instead.
if(drawable==null)
return;
int size=Math.round(paint.descent()-paint.ascent());
Rect bounds=drawable.getBounds();
int dw=drawable.getIntrinsicWidth();
int dh=drawable.getIntrinsicHeight();
if(bounds.left!=0 || bounds.top!=0 || bounds.right!=dw || bounds.left!=dh){
drawable.setBounds(0, 0, dw, dh);
}
canvas.save();
float radius = size / 2f;
Path clipPath = new Path();
clipPath.addCircle(x + radius, top + radius, radius, Path.Direction.CW);
canvas.clipPath(clipPath);
canvas.translate(x, top);
canvas.scale(size/(float)dw, size/(float)dh, 0f, 0f);
drawable.draw(canvas);
canvas.restore();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

public class CustomEmojiSpan extends ReplacementSpan{
public final Emoji emoji;
private Drawable drawable;
protected Drawable drawable;

public CustomEmojiSpan(Emoji emoji){
this.emoji=emoji;
Expand Down
Loading