Show "in reply to" and add a custom emoji helper
This commit is contained in:
parent
c9078ca8d7
commit
eed64f48fe
|
@ -12,6 +12,7 @@ import android.view.ViewGroup;
|
|||
import android.widget.ImageView;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.DisplayItemsParent;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
||||
|
@ -22,6 +23,7 @@ import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
|
|||
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -40,6 +42,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||
protected DisplayItemsAdapter adapter;
|
||||
protected String accountID;
|
||||
protected PhotoViewer currentPhotoViewer;
|
||||
protected HashMap<String, Account> knownAccounts=new HashMap<>();
|
||||
|
||||
public BaseStatusListFragment(){
|
||||
super(20);
|
||||
|
@ -59,6 +62,9 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||
@Override
|
||||
public void onAppendItems(List<T> items){
|
||||
super.onAppendItems(items);
|
||||
for(T s:items){
|
||||
addAccountToKnown(s);
|
||||
}
|
||||
for(T s:items){
|
||||
displayItems.addAll(buildDisplayItems(s));
|
||||
}
|
||||
|
@ -73,6 +79,9 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||
protected void prependItems(List<T> items){
|
||||
data.addAll(0, items);
|
||||
int offset=0;
|
||||
for(T s:items){
|
||||
addAccountToKnown(s);
|
||||
}
|
||||
for(T s:items){
|
||||
List<StatusDisplayItem> toAdd=buildDisplayItems(s);
|
||||
displayItems.addAll(offset, toAdd);
|
||||
|
@ -91,6 +100,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||
}
|
||||
|
||||
protected abstract List<StatusDisplayItem> buildDisplayItems(T s);
|
||||
protected abstract void addAccountToKnown(T s);
|
||||
|
||||
@Override
|
||||
protected void onHidden(){
|
||||
|
@ -324,5 +334,15 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||
public ImageLoaderRequest getImageRequest(int position, int image){
|
||||
return displayItems.get(position).getImageRequest(image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(@NonNull BindableViewHolder<StatusDisplayItem> holder){
|
||||
if(holder instanceof ImageLoaderViewHolder){
|
||||
int count=holder.getItem().getImageCount();
|
||||
for(int i=0;i<count;i++){
|
||||
((ImageLoaderViewHolder) holder).clearImage(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,9 +31,9 @@ public class NotificationsFragment extends BaseStatusListFragment<Notification>{
|
|||
case FAVORITE -> getString(R.string.user_favorited, n.account.displayName);
|
||||
case POLL -> getString(R.string.poll_ended);
|
||||
case STATUS -> getString(R.string.user_posted, n.account.displayName);
|
||||
});
|
||||
}, n.account.emojis, R.drawable.ic_fluent_arrow_reply_20_filled);
|
||||
if(n.status!=null){
|
||||
ArrayList<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, n.status, accountID, n);
|
||||
ArrayList<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, n.status, accountID, n, knownAccounts);
|
||||
items.add(0, titleItem);
|
||||
return items;
|
||||
}else{
|
||||
|
@ -41,6 +41,14 @@ public class NotificationsFragment extends BaseStatusListFragment<Notification>{
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addAccountToKnown(Notification s){
|
||||
if(!knownAccounts.containsKey(s.account.id))
|
||||
knownAccounts.put(s.account.id, s.account);
|
||||
if(s.status!=null && !knownAccounts.containsKey(s.status.account.id))
|
||||
knownAccounts.put(s.status.account.id, s.status.account);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLoadData(int offset, int count){
|
||||
new GetNotifications(offset>0 ? getMaxID() : null, count)
|
||||
|
|
|
@ -16,7 +16,13 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
|
||||
public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
||||
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
||||
return StatusDisplayItem.buildItems(this, s, accountID, s);
|
||||
return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addAccountToKnown(Status s){
|
||||
if(!knownAccounts.containsKey(s.account.id))
|
||||
knownAccounts.put(s.account.id, s.account);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package org.joinmastodon.android.ui.displayitems;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Spanned;
|
||||
|
||||
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
|
||||
class CustomEmojiHelper{
|
||||
public List<List<CustomEmojiSpan>> spans=new ArrayList<>();
|
||||
public List<ImageLoaderRequest> requests=new ArrayList<>();
|
||||
|
||||
public void setText(CharSequence text){
|
||||
spans.clear();
|
||||
requests.clear();
|
||||
if(!(text instanceof Spanned))
|
||||
return;
|
||||
CustomEmojiSpan[] spans=((Spanned) text).getSpans(0, text.length(), CustomEmojiSpan.class);
|
||||
for(List<CustomEmojiSpan> group:Arrays.stream(spans).collect(Collectors.groupingBy(s->s.emoji)).values()){
|
||||
this.spans.add(group);
|
||||
requests.add(group.get(0).createImageLoaderRequest());
|
||||
}
|
||||
}
|
||||
|
||||
public int getImageCount(){
|
||||
return requests.size();
|
||||
}
|
||||
|
||||
public ImageLoaderRequest getImageRequest(int image){
|
||||
return requests.get(image);
|
||||
}
|
||||
|
||||
public void setImageDrawable(int image, Drawable drawable){
|
||||
for(CustomEmojiSpan span:spans.get(image)){
|
||||
span.setDrawable(drawable);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@ import android.graphics.drawable.Animatable;
|
|||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOutlineProvider;
|
||||
|
@ -18,7 +17,6 @@ import org.joinmastodon.android.R;
|
|||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
|
||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.parceler.Parcels;
|
||||
|
@ -29,7 +27,6 @@ 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.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
|
@ -38,8 +35,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||
private ImageLoaderRequest avaRequest;
|
||||
private Fragment parentFragment;
|
||||
private String accountID;
|
||||
private ImageLoaderRequest[] emojiRequests;
|
||||
private CustomEmojiSpan[] emojiSpans;
|
||||
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
||||
private SpannableStringBuilder parsedName;
|
||||
|
||||
public HeaderStatusDisplayItem(String parentID, Account user, Instant createdAt, BaseStatusListFragment parentFragment, String accountID){
|
||||
|
@ -51,11 +47,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||
this.accountID=accountID;
|
||||
parsedName=new SpannableStringBuilder(user.displayName);
|
||||
HtmlParser.parseCustomEmoji(parsedName, user.emojis);
|
||||
emojiSpans=parsedName.getSpans(0, parsedName.length(), CustomEmojiSpan.class);
|
||||
emojiRequests=new ImageLoaderRequest[emojiSpans.length];
|
||||
for(int i=0; i<emojiSpans.length; i++){
|
||||
emojiRequests[i]=emojiSpans[i].createImageLoaderRequest();
|
||||
}
|
||||
emojiHelper.setText(parsedName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -65,13 +57,13 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||
|
||||
@Override
|
||||
public int getImageCount(){
|
||||
return 1+emojiRequests.length;
|
||||
return 1+emojiHelper.getImageCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageLoaderRequest getImageRequest(int index){
|
||||
if(index>0){
|
||||
return emojiRequests[index-1];
|
||||
return emojiHelper.getImageRequest(index-1);
|
||||
}
|
||||
return avaRequest;
|
||||
}
|
||||
|
@ -110,7 +102,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||
@Override
|
||||
public void setImage(int index, Drawable drawable){
|
||||
if(index>0){
|
||||
item.emojiSpans[index-1].setDrawable(drawable);
|
||||
item.emojiHelper.setImageDrawable(index-1, drawable);
|
||||
}else{
|
||||
avatar.setImageDrawable(drawable);
|
||||
}
|
||||
|
|
|
@ -1,22 +1,37 @@
|
|||
package org.joinmastodon.android.ui.displayitems;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||
import org.joinmastodon.android.model.Emoji;
|
||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
|
||||
public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
||||
private CharSequence text;
|
||||
@DrawableRes
|
||||
private int icon;
|
||||
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
||||
|
||||
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text){
|
||||
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon){
|
||||
super(parentID, parentFragment);
|
||||
this.text=text;
|
||||
SpannableStringBuilder ssb=new SpannableStringBuilder(text);
|
||||
HtmlParser.parseCustomEmoji(ssb, emojis);
|
||||
this.text=ssb;
|
||||
emojiHelper.setText(ssb);
|
||||
this.icon=icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -24,7 +39,17 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
|||
return Type.REBLOG_OR_REPLY_LINE;
|
||||
}
|
||||
|
||||
public static class Holder extends StatusDisplayItem.Holder<ReblogOrReplyLineStatusDisplayItem>{
|
||||
@Override
|
||||
public int getImageCount(){
|
||||
return emojiHelper.getImageCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageLoaderRequest getImageRequest(int index){
|
||||
return emojiHelper.getImageRequest(index);
|
||||
}
|
||||
|
||||
public static class Holder extends StatusDisplayItem.Holder<ReblogOrReplyLineStatusDisplayItem> implements ImageLoaderViewHolder{
|
||||
private final TextView text;
|
||||
public Holder(Activity activity, ViewGroup parent){
|
||||
super(activity, R.layout.display_item_reblog_or_reply_line, parent);
|
||||
|
@ -36,6 +61,17 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
|||
@Override
|
||||
public void onBind(ReblogOrReplyLineStatusDisplayItem item){
|
||||
text.setText(item.text);
|
||||
text.setCompoundDrawablesRelativeWithIntrinsicBounds(item.icon, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(int index, Drawable image){
|
||||
item.emojiHelper.setImageDrawable(index, image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearImage(int index){
|
||||
setImage(index, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.joinmastodon.android.ui.displayitems;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
@ -9,12 +8,15 @@ import android.view.ViewGroup;
|
|||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Attachment;
|
||||
import org.joinmastodon.android.model.DisplayItemsParent;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
|
@ -51,12 +53,15 @@ public abstract class StatusDisplayItem{
|
|||
};
|
||||
}
|
||||
|
||||
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment fragment, Status status, String accountID, DisplayItemsParent parentObject){
|
||||
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts){
|
||||
String parentID=parentObject.getID();
|
||||
ArrayList<StatusDisplayItem> items=new ArrayList<>();
|
||||
Status statusForContent=status.getContentStatus();
|
||||
if(status.reblog!=null){
|
||||
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, fragment.getString(R.string.user_boosted, status.account.displayName)));
|
||||
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, fragment.getString(R.string.user_boosted, status.account.displayName), status.account.emojis, R.drawable.ic_fluent_arrow_repeat_all_20_filled));
|
||||
}else if(status.inReplyToAccountId!=null && knownAccounts.containsKey(status.inReplyToAccountId)){
|
||||
Account account=Objects.requireNonNull(knownAccounts.get(status.inReplyToAccountId));
|
||||
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, fragment.getString(R.string.in_reply_to, account.displayName), account.emojis, R.drawable.ic_fluent_arrow_reply_20_filled));
|
||||
}
|
||||
items.add(new HeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID));
|
||||
if(!TextUtils.isEmpty(statusForContent.content))
|
||||
|
|
|
@ -4,41 +4,25 @@ import android.app.Activity;
|
|||
import android.app.Fragment;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Spanned;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
|
||||
import org.joinmastodon.android.ui.text.LinkSpan;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.views.LinkedTextView;
|
||||
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.MovieDrawable;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
private CharSequence text;
|
||||
private ImageLoaderRequest[] emojiRequests;
|
||||
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
||||
private Fragment parentFragment;
|
||||
public TextStatusDisplayItem(String parentID, CharSequence text, BaseStatusListFragment parentFragment){
|
||||
super(parentID, parentFragment);
|
||||
this.text=text;
|
||||
this.parentFragment=parentFragment;
|
||||
if(text instanceof Spanned){
|
||||
CustomEmojiSpan[] emojiSpans=((Spanned) text).getSpans(0, text.length(), CustomEmojiSpan.class);
|
||||
emojiRequests=new ImageLoaderRequest[emojiSpans.length];
|
||||
for(int i=0; i<emojiSpans.length; i++){
|
||||
emojiRequests[i]=emojiSpans[i].createImageLoaderRequest();
|
||||
}
|
||||
}else{
|
||||
emojiRequests=new ImageLoaderRequest[0];
|
||||
}
|
||||
emojiHelper.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,17 +32,16 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
|||
|
||||
@Override
|
||||
public int getImageCount(){
|
||||
return emojiRequests.length;
|
||||
return emojiHelper.getImageCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageLoaderRequest getImageRequest(int index){
|
||||
return emojiRequests[index];
|
||||
return emojiHelper.getImageRequest(index);
|
||||
}
|
||||
|
||||
public static class Holder extends StatusDisplayItem.Holder<TextStatusDisplayItem> implements ImageLoaderViewHolder{
|
||||
private final LinkedTextView text;
|
||||
private CustomEmojiSpan[] emojiSpans;
|
||||
|
||||
public Holder(Activity activity, ViewGroup parent){
|
||||
super(activity, R.layout.display_item_text, parent);
|
||||
|
@ -68,21 +51,12 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
|||
@Override
|
||||
public void onBind(TextStatusDisplayItem item){
|
||||
text.setText(item.text);
|
||||
if(emojiSpans!=null){
|
||||
for(CustomEmojiSpan span:emojiSpans){
|
||||
span.setDrawable(null);
|
||||
}
|
||||
}
|
||||
if(item.text instanceof Spanned)
|
||||
emojiSpans=((Spanned) item.text).getSpans(0, item.text.length(), CustomEmojiSpan.class);
|
||||
else
|
||||
emojiSpans=new CustomEmojiSpan[0];
|
||||
text.setInvalidateOnEveryFrame(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(int index, Drawable image){
|
||||
emojiSpans[index].setDrawable(image);
|
||||
item.emojiHelper.setImageDrawable(index, image);
|
||||
text.invalidate();
|
||||
if(image instanceof Animatable){
|
||||
((Animatable) image).start();
|
||||
|
@ -93,7 +67,7 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
|||
|
||||
@Override
|
||||
public void clearImage(int index){
|
||||
emojiSpans[index].setDrawable(null);
|
||||
item.emojiHelper.setImageDrawable(index, null);
|
||||
text.invalidate();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue