Custom emoji in more places
This commit is contained in:
parent
82a8d0cc29
commit
c9078ca8d7
|
@ -5,6 +5,7 @@ import android.content.Context;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Outline;
|
import android.graphics.Outline;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.graphics.drawable.ShapeDrawable;
|
import android.graphics.drawable.ShapeDrawable;
|
||||||
import android.graphics.drawable.shapes.RoundRectShape;
|
import android.graphics.drawable.shapes.RoundRectShape;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -17,6 +18,7 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.model.AccountField;
|
import org.joinmastodon.android.model.AccountField;
|
||||||
|
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
|
||||||
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
||||||
import org.joinmastodon.android.ui.views.LinkedTextView;
|
import org.joinmastodon.android.ui.views.LinkedTextView;
|
||||||
|
|
||||||
|
@ -28,7 +30,11 @@ import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||||
|
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||||
import me.grishka.appkit.imageloader.ListImageLoaderWrapper;
|
import me.grishka.appkit.imageloader.ListImageLoaderWrapper;
|
||||||
|
import me.grishka.appkit.imageloader.RecyclerViewDelegate;
|
||||||
|
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||||
import me.grishka.appkit.utils.BindableViewHolder;
|
import me.grishka.appkit.utils.BindableViewHolder;
|
||||||
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
@ -44,6 +50,7 @@ public class ProfileAboutFragment extends Fragment{
|
||||||
private boolean isInEditMode;
|
private boolean isInEditMode;
|
||||||
private ItemTouchHelper dragHelper=new ItemTouchHelper(new ReorderCallback());
|
private ItemTouchHelper dragHelper=new ItemTouchHelper(new ReorderCallback());
|
||||||
private RecyclerView.ViewHolder draggedViewHolder;
|
private RecyclerView.ViewHolder draggedViewHolder;
|
||||||
|
private ListImageLoaderWrapper imgLoader;
|
||||||
|
|
||||||
public void setFields(List<AccountField> fields){
|
public void setFields(List<AccountField> fields){
|
||||||
this.fields=fields;
|
this.fields=fields;
|
||||||
|
@ -61,6 +68,7 @@ public class ProfileAboutFragment extends Fragment{
|
||||||
list=new UsableRecyclerView(getActivity());
|
list=new UsableRecyclerView(getActivity());
|
||||||
list.setId(R.id.list);
|
list.setId(R.id.list);
|
||||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
|
imgLoader=new ListImageLoaderWrapper(getActivity(), list, new RecyclerViewDelegate(list), null);
|
||||||
list.setAdapter(adapter=new AboutAdapter());
|
list.setAdapter(adapter=new AboutAdapter());
|
||||||
int pad=V.dp(16);
|
int pad=V.dp(16);
|
||||||
list.setPadding(pad, pad, pad, pad);
|
list.setPadding(pad, pad, pad, pad);
|
||||||
|
@ -95,9 +103,9 @@ public class ProfileAboutFragment extends Fragment{
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AboutAdapter extends UsableRecyclerView.Adapter<BaseViewHolder>{
|
private class AboutAdapter extends UsableRecyclerView.Adapter<BaseViewHolder> implements ImageLoaderRecyclerAdapter{
|
||||||
public AboutAdapter(){
|
public AboutAdapter(){
|
||||||
super(null);
|
super(imgLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -139,6 +147,16 @@ public class ProfileAboutFragment extends Fragment{
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getImageCountForItem(int position){
|
||||||
|
return isInEditMode || fields.get(position).emojiRequests==null ? 0 : fields.get(position).emojiRequests.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImageLoaderRequest getImageRequest(int position, int image){
|
||||||
|
return fields.get(position).emojiRequests.get(image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private abstract class BaseViewHolder extends BindableViewHolder<AccountField>{
|
private abstract class BaseViewHolder extends BindableViewHolder<AccountField>{
|
||||||
|
@ -164,7 +182,7 @@ public class ProfileAboutFragment extends Fragment{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AboutViewHolder extends BaseViewHolder{
|
private class AboutViewHolder extends BaseViewHolder implements ImageLoaderViewHolder{
|
||||||
private TextView title;
|
private TextView title;
|
||||||
private LinkedTextView value;
|
private LinkedTextView value;
|
||||||
|
|
||||||
|
@ -177,9 +195,22 @@ public class ProfileAboutFragment extends Fragment{
|
||||||
@Override
|
@Override
|
||||||
public void onBind(AccountField item){
|
public void onBind(AccountField item){
|
||||||
super.onBind(item);
|
super.onBind(item);
|
||||||
title.setText(item.name);
|
title.setText(item.parsedName);
|
||||||
value.setText(item.parsedValue);
|
value.setText(item.parsedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setImage(int index, Drawable image){
|
||||||
|
CustomEmojiSpan span=index>=item.nameEmojis.length ? item.valueEmojis[index-item.nameEmojis.length] : item.nameEmojis[index];
|
||||||
|
span.setDrawable(image);
|
||||||
|
title.invalidate();
|
||||||
|
value.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearImage(int index){
|
||||||
|
setImage(index, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class EditableAboutViewHolder extends BaseViewHolder{
|
private class EditableAboutViewHolder extends BaseViewHolder{
|
||||||
|
|
|
@ -12,6 +12,7 @@ import android.graphics.Outline;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
@ -42,6 +43,7 @@ import org.joinmastodon.android.model.Relationship;
|
||||||
import org.joinmastodon.android.ui.drawables.CoverOverlayGradientDrawable;
|
import org.joinmastodon.android.ui.drawables.CoverOverlayGradientDrawable;
|
||||||
import org.joinmastodon.android.ui.tabs.TabLayout;
|
import org.joinmastodon.android.ui.tabs.TabLayout;
|
||||||
import org.joinmastodon.android.ui.tabs.TabLayoutMediator;
|
import org.joinmastodon.android.ui.tabs.TabLayoutMediator;
|
||||||
|
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
|
||||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.CoverImageView;
|
import org.joinmastodon.android.ui.views.CoverImageView;
|
||||||
|
@ -266,7 +268,10 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||||
setSubtitle(getResources().getQuantityString(R.plurals.x_posts, account.statusesCount, account.statusesCount));
|
setSubtitle(getResources().getQuantityString(R.plurals.x_posts, account.statusesCount, account.statusesCount));
|
||||||
ViewImageLoader.load(avatar, null, new UrlImageLoaderRequest(account.avatar, V.dp(100), V.dp(100)));
|
ViewImageLoader.load(avatar, null, new UrlImageLoaderRequest(account.avatar, V.dp(100), V.dp(100)));
|
||||||
ViewImageLoader.load(cover, null, new UrlImageLoaderRequest(account.header, 1000, 1000));
|
ViewImageLoader.load(cover, null, new UrlImageLoaderRequest(account.header, 1000, 1000));
|
||||||
name.setText(account.displayName);
|
SpannableStringBuilder ssb=new SpannableStringBuilder(account.displayName);
|
||||||
|
HtmlParser.parseCustomEmoji(ssb, account.emojis);
|
||||||
|
name.setText(ssb);
|
||||||
|
setTitle(ssb);
|
||||||
username.setText('@'+account.acct);
|
username.setText('@'+account.acct);
|
||||||
bio.setText(HtmlParser.parse(account.note, account.emojis));
|
bio.setText(HtmlParser.parse(account.note, account.emojis));
|
||||||
followersCount.setText(UiUtils.abbreviateNumber(account.followersCount));
|
followersCount.setText(UiUtils.abbreviateNumber(account.followersCount));
|
||||||
|
@ -276,6 +281,9 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||||
followingLabel.setText(getResources().getQuantityString(R.plurals.following, account.followingCount));
|
followingLabel.setText(getResources().getQuantityString(R.plurals.following, account.followingCount));
|
||||||
postsLabel.setText(getResources().getQuantityString(R.plurals.posts, account.statusesCount));
|
postsLabel.setText(getResources().getQuantityString(R.plurals.posts, account.statusesCount));
|
||||||
|
|
||||||
|
UiUtils.loadCustomEmojiInTextView(name);
|
||||||
|
UiUtils.loadCustomEmojiInTextView(bio);
|
||||||
|
|
||||||
if(AccountSessionManager.getInstance().isSelf(accountID, account)){
|
if(AccountSessionManager.getInstance().isSelf(accountID, account)){
|
||||||
actionButton.setText(R.string.edit_profile);
|
actionButton.setText(R.string.edit_profile);
|
||||||
}else{
|
}else{
|
||||||
|
@ -285,12 +293,24 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||||
fields.clear();
|
fields.clear();
|
||||||
|
|
||||||
AccountField joined=new AccountField();
|
AccountField joined=new AccountField();
|
||||||
joined.name=getString(R.string.profile_joined);
|
joined.parsedName=joined.name=getString(R.string.profile_joined);
|
||||||
joined.parsedValue=joined.value=DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(LocalDateTime.ofInstant(account.createdAt, ZoneId.systemDefault()));
|
joined.parsedValue=joined.value=DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(LocalDateTime.ofInstant(account.createdAt, ZoneId.systemDefault()));
|
||||||
fields.add(joined);
|
fields.add(joined);
|
||||||
|
|
||||||
for(AccountField field:account.fields){
|
for(AccountField field:account.fields){
|
||||||
field.parsedValue=HtmlParser.parse(field.value, account.emojis);
|
field.parsedValue=ssb=HtmlParser.parse(field.value, account.emojis);
|
||||||
|
field.valueEmojis=ssb.getSpans(0, ssb.length(), CustomEmojiSpan.class);
|
||||||
|
ssb=new SpannableStringBuilder(field.name);
|
||||||
|
HtmlParser.parseCustomEmoji(ssb, account.emojis);
|
||||||
|
field.parsedName=ssb;
|
||||||
|
field.nameEmojis=ssb.getSpans(0, ssb.length(), CustomEmojiSpan.class);
|
||||||
|
field.emojiRequests=new ArrayList<>(field.nameEmojis.length+field.valueEmojis.length);
|
||||||
|
for(CustomEmojiSpan span:field.nameEmojis){
|
||||||
|
field.emojiRequests.add(span.createImageLoaderRequest());
|
||||||
|
}
|
||||||
|
for(CustomEmojiSpan span:field.valueEmojis){
|
||||||
|
field.emojiRequests.add(span.createImageLoaderRequest());
|
||||||
|
}
|
||||||
fields.add(field);
|
fields.add(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
package org.joinmastodon.android.model;
|
package org.joinmastodon.android.model;
|
||||||
|
|
||||||
import org.joinmastodon.android.api.RequiredField;
|
import org.joinmastodon.android.api.RequiredField;
|
||||||
|
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
|
||||||
import org.parceler.Parcel;
|
import org.parceler.Parcel;
|
||||||
import org.parceler.Transient;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a profile field as a name-value pair with optional verification.
|
* Represents a profile field as a name-value pair with optional verification.
|
||||||
|
@ -26,7 +29,9 @@ public class AccountField extends BaseModel{
|
||||||
*/
|
*/
|
||||||
public Instant verifiedAt;
|
public Instant verifiedAt;
|
||||||
|
|
||||||
public transient CharSequence parsedValue;
|
public transient CharSequence parsedValue, parsedName;
|
||||||
|
public transient CustomEmojiSpan[] valueEmojis, nameEmojis;
|
||||||
|
public transient ArrayList<UrlImageLoaderRequest> emojiRequests;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
|
|
|
@ -6,6 +6,8 @@ import android.graphics.Outline;
|
||||||
import android.graphics.drawable.Animatable;
|
import android.graphics.drawable.Animatable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
|
import android.text.Spanned;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewOutlineProvider;
|
import android.view.ViewOutlineProvider;
|
||||||
|
@ -16,6 +18,8 @@ import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
import org.joinmastodon.android.model.Account;
|
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.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
|
@ -34,6 +38,9 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
private ImageLoaderRequest avaRequest;
|
private ImageLoaderRequest avaRequest;
|
||||||
private Fragment parentFragment;
|
private Fragment parentFragment;
|
||||||
private String accountID;
|
private String accountID;
|
||||||
|
private ImageLoaderRequest[] emojiRequests;
|
||||||
|
private CustomEmojiSpan[] emojiSpans;
|
||||||
|
private SpannableStringBuilder parsedName;
|
||||||
|
|
||||||
public HeaderStatusDisplayItem(String parentID, Account user, Instant createdAt, BaseStatusListFragment parentFragment, String accountID){
|
public HeaderStatusDisplayItem(String parentID, Account user, Instant createdAt, BaseStatusListFragment parentFragment, String accountID){
|
||||||
super(parentID, parentFragment);
|
super(parentID, parentFragment);
|
||||||
|
@ -42,6 +49,13 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
avaRequest=new UrlImageLoaderRequest(user.avatar);
|
avaRequest=new UrlImageLoaderRequest(user.avatar);
|
||||||
this.parentFragment=parentFragment;
|
this.parentFragment=parentFragment;
|
||||||
this.accountID=accountID;
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -51,11 +65,14 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getImageCount(){
|
public int getImageCount(){
|
||||||
return 1;
|
return 1+emojiRequests.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImageLoaderRequest getImageRequest(int index){
|
public ImageLoaderRequest getImageRequest(int index){
|
||||||
|
if(index>0){
|
||||||
|
return emojiRequests[index-1];
|
||||||
|
}
|
||||||
return avaRequest;
|
return avaRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,21 +102,25 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBind(HeaderStatusDisplayItem item){
|
public void onBind(HeaderStatusDisplayItem item){
|
||||||
name.setText(item.user.displayName);
|
name.setText(item.parsedName);
|
||||||
username.setText('@'+item.user.acct);
|
username.setText('@'+item.user.acct);
|
||||||
timestamp.setText(UiUtils.formatRelativeTimestamp(itemView.getContext(), item.createdAt));
|
timestamp.setText(UiUtils.formatRelativeTimestamp(itemView.getContext(), item.createdAt));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setImage(int index, Drawable drawable){
|
public void setImage(int index, Drawable drawable){
|
||||||
avatar.setImageDrawable(drawable);
|
if(index>0){
|
||||||
|
item.emojiSpans[index-1].setDrawable(drawable);
|
||||||
|
}else{
|
||||||
|
avatar.setImageDrawable(drawable);
|
||||||
|
}
|
||||||
if(drawable instanceof Animatable)
|
if(drawable instanceof Animatable)
|
||||||
((Animatable) drawable).start();
|
((Animatable) drawable).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearImage(int index){
|
public void clearImage(int index){
|
||||||
avatar.setImageBitmap(null);
|
setImage(index, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onAvaClick(View v){
|
private void onAvaClick(View v){
|
||||||
|
|
|
@ -33,9 +33,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||||
if(text instanceof Spanned){
|
if(text instanceof Spanned){
|
||||||
CustomEmojiSpan[] emojiSpans=((Spanned) text).getSpans(0, text.length(), CustomEmojiSpan.class);
|
CustomEmojiSpan[] emojiSpans=((Spanned) text).getSpans(0, text.length(), CustomEmojiSpan.class);
|
||||||
emojiRequests=new ImageLoaderRequest[emojiSpans.length];
|
emojiRequests=new ImageLoaderRequest[emojiSpans.length];
|
||||||
int emojiSize=V.dp(20);
|
|
||||||
for(int i=0; i<emojiSpans.length; i++){
|
for(int i=0; i<emojiSpans.length; i++){
|
||||||
emojiRequests[i]=new UrlImageLoaderRequest(emojiSpans[i].emoji.url, emojiSize, emojiSize);
|
emojiRequests[i]=emojiSpans[i].createImageLoaderRequest();
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
emojiRequests=new ImageLoaderRequest[0];
|
emojiRequests=new ImageLoaderRequest[0];
|
||||||
|
|
|
@ -10,6 +10,8 @@ import org.joinmastodon.android.model.Emoji;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||||
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class CustomEmojiSpan extends ReplacementSpan{
|
public class CustomEmojiSpan extends ReplacementSpan{
|
||||||
public final Emoji emoji;
|
public final Emoji emoji;
|
||||||
|
@ -48,4 +50,9 @@ public class CustomEmojiSpan extends ReplacementSpan{
|
||||||
public void setDrawable(Drawable drawable){
|
public void setDrawable(Drawable drawable){
|
||||||
this.drawable=drawable;
|
this.drawable=drawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UrlImageLoaderRequest createImageLoaderRequest(){
|
||||||
|
int size=V.dp(20);
|
||||||
|
return new UrlImageLoaderRequest(emoji.url, size, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,23 +2,34 @@ package org.joinmastodon.android.ui.utils;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.graphics.drawable.Animatable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.provider.OpenableColumns;
|
import android.provider.OpenableColumns;
|
||||||
|
import android.text.Spanned;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.joinmastodon.android.MastodonApp;
|
import org.joinmastodon.android.MastodonApp;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.model.Emoji;
|
||||||
|
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import androidx.annotation.ColorRes;
|
import androidx.annotation.ColorRes;
|
||||||
import androidx.browser.customtabs.CustomTabsIntent;
|
import androidx.browser.customtabs.CustomTabsIntent;
|
||||||
|
import me.grishka.appkit.imageloader.ViewImageLoader;
|
||||||
|
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||||
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class UiUtils{
|
public class UiUtils{
|
||||||
private static Handler mainHandler=new Handler(Looper.getMainLooper());
|
private static Handler mainHandler=new Handler(Looper.getMainLooper());
|
||||||
|
@ -93,4 +104,34 @@ public class UiUtils{
|
||||||
}
|
}
|
||||||
return uri.getLastPathSegment();
|
return uri.getLastPathSegment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void loadCustomEmojiInTextView(TextView view){
|
||||||
|
CharSequence _text=view.getText();
|
||||||
|
if(!(_text instanceof Spanned))
|
||||||
|
return;
|
||||||
|
Spanned text=(Spanned)_text;
|
||||||
|
CustomEmojiSpan[] spans=text.getSpans(0, text.length(), CustomEmojiSpan.class);
|
||||||
|
if(spans.length==0)
|
||||||
|
return;
|
||||||
|
int emojiSize=V.dp(20);
|
||||||
|
Map<Emoji, List<CustomEmojiSpan>> spansByEmoji=Arrays.stream(spans).collect(Collectors.groupingBy(s->s.emoji));
|
||||||
|
for(Map.Entry<Emoji, List<CustomEmojiSpan>> emoji:spansByEmoji.entrySet()){
|
||||||
|
ViewImageLoader.load(new ViewImageLoader.Target(){
|
||||||
|
@Override
|
||||||
|
public void setImageDrawable(Drawable d){
|
||||||
|
if(d==null)
|
||||||
|
return;
|
||||||
|
for(CustomEmojiSpan span:emoji.getValue()){
|
||||||
|
span.setDrawable(d);
|
||||||
|
}
|
||||||
|
view.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(){
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}, null, new UrlImageLoaderRequest(emoji.getKey().url, emojiSize, emojiSize), null, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue