diff --git a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java index 0a88e8d44..dc06ddcfc 100644 --- a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java @@ -268,86 +268,74 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana } }); } else if (statusDraft != null) {//Restore a draft with all messages - new Thread(() -> { - if (statusDraft.statusReplyList != null) { - statusDraft.statusReplyList = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusDraft.statusReplyList); - } - Handler mainHandler = new Handler(Looper.getMainLooper()); - Runnable myRunnable = () -> { - if (statusDraft.statusReplyList != null) { - statusList.addAll(statusDraft.statusReplyList); - binding.recyclerView.addItemDecoration(new DividerDecorationSimple(ComposeActivity.this, statusList)); - } - int statusCount = statusList.size(); - statusList.addAll(statusDraft.statusDraftList); - composeAdapter = new ComposeAdapter(statusList, statusCount, account, accountMention, visibility); - composeAdapter.manageDrafts = this; - LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this); - binding.recyclerView.setLayoutManager(mLayoutManager); - binding.recyclerView.setAdapter(composeAdapter); - binding.recyclerView.scrollToPosition(composeAdapter.getItemCount() - 1); - }; - mainHandler.post(myRunnable); - }).start(); + if (statusDraft.statusReplyList != null) { + statusDraft.statusReplyList = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusDraft.statusReplyList); + } + if (statusDraft.statusReplyList != null) { + statusList.addAll(statusDraft.statusReplyList); + binding.recyclerView.addItemDecoration(new DividerDecorationSimple(ComposeActivity.this, statusList)); + } + int statusCount = statusList.size(); + statusList.addAll(statusDraft.statusDraftList); + composeAdapter = new ComposeAdapter(statusList, statusCount, account, accountMention, visibility); + composeAdapter.manageDrafts = this; + LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this); + binding.recyclerView.setLayoutManager(mLayoutManager); + binding.recyclerView.setAdapter(composeAdapter); + binding.recyclerView.scrollToPosition(composeAdapter.getItemCount() - 1); } else if (statusReply != null) { - new Thread(() -> { - statusReply = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusReply); - Handler mainHandler = new Handler(Looper.getMainLooper()); - Runnable myRunnable = () -> { - statusList.add(statusReply); - int statusCount = statusList.size(); - statusDraftList.get(0).in_reply_to_id = statusReply.id; - //We change order for mentions - //At first place the account that has been mentioned if it's not our - statusDraftList.get(0).mentions = new ArrayList<>(); - if (!statusReply.account.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) { - Mention mention = new Mention(); - mention.acct = "@" + statusReply.account.acct; - mention.url = statusReply.account.url; - mention.username = statusReply.account.username; - statusDraftList.get(0).mentions.add(mention); - } + statusReply = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusReply); + statusList.add(statusReply); + int statusCount = statusList.size(); + statusDraftList.get(0).in_reply_to_id = statusReply.id; + //We change order for mentions + //At first place the account that has been mentioned if it's not our + statusDraftList.get(0).mentions = new ArrayList<>(); + if (!statusReply.account.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) { + Mention mention = new Mention(); + mention.acct = "@" + statusReply.account.acct; + mention.url = statusReply.account.url; + mention.username = statusReply.account.username; + statusDraftList.get(0).mentions.add(mention); + } - //There are other mentions to - if (statusReply.mentions != null && statusReply.mentions.size() > 0) { - for (Mention mentionTmp : statusReply.mentions) { - if (!mentionTmp.acct.equalsIgnoreCase(statusReply.account.acct) && !mentionTmp.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) { - statusDraftList.get(0).mentions.add(mentionTmp); - } - } + //There are other mentions to + if (statusReply.mentions != null && statusReply.mentions.size() > 0) { + for (Mention mentionTmp : statusReply.mentions) { + if (!mentionTmp.acct.equalsIgnoreCase(statusReply.account.acct) && !mentionTmp.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) { + statusDraftList.get(0).mentions.add(mentionTmp); } - if (mentionBooster != null) { - Mention mention = new Mention(); - mention.acct = mentionBooster.acct; - mention.url = mentionBooster.url; - mention.username = mentionBooster.username; - boolean present = false; - for (Mention mentionTmp : statusDraftList.get(0).mentions) { - if (mentionTmp.acct.equalsIgnoreCase(mentionBooster.acct)) { - present = true; - break; - } - } - if (!present) { - statusDraftList.get(0).mentions.add(mention); - } + } + } + if (mentionBooster != null) { + Mention mention = new Mention(); + mention.acct = mentionBooster.acct; + mention.url = mentionBooster.url; + mention.username = mentionBooster.username; + boolean present = false; + for (Mention mentionTmp : statusDraftList.get(0).mentions) { + if (mentionTmp.acct.equalsIgnoreCase(mentionBooster.acct)) { + present = true; + break; } - if (statusReply.spoiler_text != null) { - statusDraftList.get(0).spoiler_text = statusReply.spoiler_text; - } - //StatusDraftList at this point should only have one element - statusList.addAll(statusDraftList); - composeAdapter = new ComposeAdapter(statusList, statusCount, account, accountMention, visibility); - composeAdapter.manageDrafts = this; - LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this); - binding.recyclerView.setLayoutManager(mLayoutManager); - binding.recyclerView.setAdapter(composeAdapter); - statusesVM.getContext(currentInstance, BaseMainActivity.currentToken, statusReply.id) - .observe(ComposeActivity.this, this::initializeContextView); - }; - mainHandler.post(myRunnable); - }).start(); + } + if (!present) { + statusDraftList.get(0).mentions.add(mention); + } + } + if (statusReply.spoiler_text != null) { + statusDraftList.get(0).spoiler_text = statusReply.spoiler_text; + } + //StatusDraftList at this point should only have one element + statusList.addAll(statusDraftList); + composeAdapter = new ComposeAdapter(statusList, statusCount, account, accountMention, visibility); + composeAdapter.manageDrafts = this; + LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this); + binding.recyclerView.setLayoutManager(mLayoutManager); + binding.recyclerView.setAdapter(composeAdapter); + statusesVM.getContext(currentInstance, BaseMainActivity.currentToken, statusReply.id) + .observe(ComposeActivity.this, this::initializeContextView); } else { //Compose without replying statusList.addAll(statusDraftList); @@ -359,7 +347,6 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana if (statusMention != null) { composeAdapter.loadMentions(statusMention); } - } MastodonHelper.loadPPMastodon(binding.profilePicture, account.mastodon_account); LocalBroadcastManager.getInstance(this) diff --git a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java index 1226c83d2..303b9f79e 100644 --- a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java @@ -32,6 +32,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.text.Html; +import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; import android.text.method.LinkMovementMethod; @@ -89,6 +90,7 @@ import app.fedilab.android.client.entities.app.WellKnownNodeinfo; import app.fedilab.android.databinding.ActivityProfileBinding; import app.fedilab.android.exception.DBException; import app.fedilab.android.helper.CrossActionHelper; +import app.fedilab.android.helper.CustomEmoji; import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.MastodonHelper; import app.fedilab.android.helper.SpannableHelper; @@ -362,7 +364,9 @@ public class ProfileActivity extends BaseActivity { if (account.span_display_name == null && account.display_name == null) { binding.accountDn.setText(account.username); } else { - binding.accountDn.setText(account.span_display_name != null ? account.span_display_name : account.display_name, TextView.BufferType.SPANNABLE); + Spannable textAccount = account.span_display_name != null ? account.span_display_name : new SpannableString(account.display_name); + CustomEmoji.displayEmoji(ProfileActivity.this, account.emojis, textAccount, binding.accountDn, null, null); + binding.accountDn.setText(textAccount, TextView.BufferType.SPANNABLE); } binding.accountUn.setText(String.format("@%s", account.acct)); @@ -377,12 +381,13 @@ public class ProfileActivity extends BaseActivity { clipboard.setPrimaryClip(clip); return false; }); - + Spannable textNote; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - binding.accountNote.setText(account.span_note != null ? account.span_note : new SpannableString(Html.fromHtml(account.note, Html.FROM_HTML_MODE_COMPACT)), TextView.BufferType.SPANNABLE); + textNote = account.span_note != null ? account.span_note : new SpannableString(Html.fromHtml(account.note, Html.FROM_HTML_MODE_COMPACT)); else - binding.accountNote.setText(account.span_note != null ? account.span_note : new SpannableString(Html.fromHtml(account.note)), TextView.BufferType.SPANNABLE); - + textNote = account.span_note != null ? account.span_note : new SpannableString(Html.fromHtml(account.note)); + CustomEmoji.displayEmoji(ProfileActivity.this, account.emojis, textNote, binding.accountNote, null, null); + binding.accountNote.setText(textNote, TextView.BufferType.SPANNABLE); binding.accountNote.setMovementMethod(LinkMovementMethod.getInstance()); MastodonHelper.loadPPMastodon(binding.accountPp, account); diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Account.java b/app/src/main/java/app/fedilab/android/client/entities/api/Account.java index 0f253477a..012314ab7 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Account.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Account.java @@ -78,7 +78,7 @@ public class Account implements Serializable { public transient Spannable span_display_name; public transient Spannable span_note; public transient RelationShip relationShip; - public boolean emojiFetched = false; + public transient boolean emojiFetched = false; public static class AccountParams implements Serializable { @SerializedName("discoverable") diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Announcement.java b/app/src/main/java/app/fedilab/android/client/entities/api/Announcement.java index 4669833d7..287e245ee 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Announcement.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Announcement.java @@ -51,4 +51,5 @@ public class Announcement { //Some extra spannable element - They will be filled automatically when fetching the status public transient Spannable span_content; + public boolean emojiFetched = false; } diff --git a/app/src/main/java/app/fedilab/android/helper/CustomEmoji.java b/app/src/main/java/app/fedilab/android/helper/CustomEmoji.java index 801625f45..6f3745250 100644 --- a/app/src/main/java/app/fedilab/android/helper/CustomEmoji.java +++ b/app/src/main/java/app/fedilab/android/helper/CustomEmoji.java @@ -16,6 +16,7 @@ package app.fedilab.android.helper; import android.content.Context; import android.content.SharedPreferences; +import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.text.Spannable; import android.text.style.ImageSpan; @@ -28,7 +29,6 @@ import androidx.preference.PreferenceManager; import com.bumptech.glide.Glide; import com.bumptech.glide.request.target.CustomTarget; import com.bumptech.glide.request.transition.Transition; -import com.github.penfeizhou.animation.apng.APNGDrawable; import java.util.List; import java.util.regex.Matcher; @@ -54,13 +54,16 @@ public class CustomEmoji { @Override public void onLoadFailed(@Nullable Drawable errorDrawable) { super.onLoadFailed(errorDrawable); - if (finalCount == emojis.size()) { + if (finalCount == emojis.size() && listener != null) { listener.allEmojisfound(id); } } @Override public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { + if (content == null) { + return; + } Matcher matcher = Pattern.compile(":" + emoji.shortcode + ":", Pattern.LITERAL) .matcher(content); while (matcher.find()) { @@ -72,7 +75,7 @@ public class CustomEmoji { imageSpan, matcher.start(), matcher.end(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); } - if (animate && resource instanceof APNGDrawable) { + if (animate && resource instanceof Animatable) { Drawable.Callback callback = resource.getCallback(); resource.setCallback(new Drawable.Callback() { @Override @@ -97,10 +100,10 @@ public class CustomEmoji { } } }); - ((APNGDrawable) resource).start(); + ((Animatable) resource).start(); } - if (finalCount == emojis.size()) { + if (finalCount == emojis.size() && listener != null) { listener.allEmojisfound(id); } } diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index aaf6264a4..3616f53ac 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -861,31 +861,29 @@ public class SpannableHelper { return statuses; } - public static List convertNitterStatus(Context context, List statuses) { + public static List convertNitterStatus(List statuses) { if (statuses != null) { for (Status status : statuses) { - convertNitterStatus(context, status); + convertNitterStatus(status); } } return statuses; } - public static Status convertNitterStatus(Context context, Status status) { + public static void convertNitterStatus(Status status) { if (status != null) { - status.span_content = SpannableHelper.convertNitter(context, status.content); + status.span_content = SpannableHelper.convertNitter(status.content); } - return status; } /** * Convert HTML content to text. Also, it handles click on link * This needs to be run asynchronously * - * @param context {@link Context} - * @param text String - text to convert, it can be content, spoiler, poll items, etc. + * @param text String - text to convert, it can be content, spoiler, poll items, etc. * @return Spannable string */ - private static Spannable convertNitter(@NonNull Context context, String text) { + private static Spannable convertNitter(String text) { SpannableString initialContent; if (text == null) { return null; @@ -924,7 +922,7 @@ public class SpannableHelper { if (status.account == null) { return status; } - status.account.span_display_name = SpannableHelper.convertA(context, status.account, status.account.display_name, true); + status.account.span_display_name = SpannableHelper.convertA(context, status.account.display_name, true); if (status.poll != null) { for (Poll.PollItem pollItem : status.poll.options) { pollItem.span_title = SpannableHelper.convert(context, status, pollItem.title, false); @@ -936,7 +934,7 @@ public class SpannableHelper { status.reblog.span_translate = SpannableHelper.convert(context, status, status.reblog.translationContent); } status.reblog.span_spoiler_text = SpannableHelper.convert(context, status, status.reblog.spoiler_text); - status.reblog.account.span_display_name = SpannableHelper.convertA(context, status.reblog.account, status.reblog.account.display_name, true); + status.reblog.account.span_display_name = SpannableHelper.convertA(context, status.reblog.account.display_name, true); if (status.reblog.poll != null) { for (Poll.PollItem pollItem : status.reblog.poll.options) { pollItem.span_title = SpannableHelper.convert(context, status, pollItem.title, false); @@ -959,12 +957,12 @@ public class SpannableHelper { public static Account convertAccount(Context context, Account account) { if (account != null) { - account.span_display_name = SpannableHelper.convertA(context, account, account.display_name, true); - account.span_note = SpannableHelper.convertA(context, account, account.note, false); + account.span_display_name = SpannableHelper.convertA(context, account.display_name, true); + account.span_note = SpannableHelper.convertA(context, account.note, false); if (account.fields != null && account.fields.size() > 0) { List fields = new ArrayList<>(); for (Field field : account.fields) { - field.value_span = SpannableHelper.convertA(context, account, field.value, false); + field.value_span = SpannableHelper.convertA(context, field.value, false); fields.add(field); } account.fields = fields; @@ -979,11 +977,10 @@ public class SpannableHelper { * This needs to be run asynchronously * * @param context {@link Context} - * @param account {@link Account} - Account concerned by the spannable transformation * @param text String - text to convert, it can be display name or bio * @return Spannable string */ - private static Spannable convertA(@NonNull Context context, @NonNull Account account, String text, boolean limitedToDisplayName) { + private static Spannable convertA(@NonNull Context context, String text, boolean limitedToDisplayName) { SpannableString initialContent; if (text == null) { return null; diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java index 6f6e053d3..05e1b2fa9 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java @@ -45,6 +45,7 @@ import app.fedilab.android.R; import app.fedilab.android.activities.ProfileActivity; import app.fedilab.android.client.entities.api.Account; import app.fedilab.android.databinding.DrawerAccountBinding; +import app.fedilab.android.helper.CustomEmoji; import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.MastodonHelper; import app.fedilab.android.viewmodel.mastodon.AccountsVM; @@ -224,8 +225,20 @@ public class AccountAdapter extends RecyclerView.Adapter { + if (!account.emojiFetched) { + account.emojiFetched = true; + accountViewHolder.binding.displayName.post(() -> adapter.notifyItemChanged(position)); + } + }); accountViewHolder.binding.displayName.setText(account.span_display_name, TextView.BufferType.SPANNABLE); accountViewHolder.binding.username.setText(String.format("@%s", account.acct)); + CustomEmoji.displayEmoji(context, account.emojis, account.span_note, accountViewHolder.binding.bio, account.id, id -> { + if (!account.emojiFetched) { + account.emojiFetched = true; + accountViewHolder.binding.bio.post(() -> adapter.notifyItemChanged(position)); + } + }); accountViewHolder.binding.bio.setText(account.span_note, TextView.BufferType.SPANNABLE); } diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/AnnouncementAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/AnnouncementAdapter.java index 4983cbda0..8ae35dafd 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/AnnouncementAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/AnnouncementAdapter.java @@ -44,6 +44,7 @@ import app.fedilab.android.R; import app.fedilab.android.client.entities.api.Announcement; import app.fedilab.android.client.entities.api.Reaction; import app.fedilab.android.databinding.DrawerAnnouncementBinding; +import app.fedilab.android.helper.CustomEmoji; import app.fedilab.android.helper.Helper; import app.fedilab.android.viewmodel.mastodon.AnnouncementsVM; @@ -87,6 +88,12 @@ public class AnnouncementAdapter extends RecyclerView.Adapter { + if (!announcement.emojiFetched) { + announcement.emojiFetched = true; + holder.binding.content.post(() -> notifyItemChanged(position)); + } + }); holder.binding.content.setText(announcement.span_content, TextView.BufferType.SPANNABLE); if (announcement.starts_at != null) { String dateIni; diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java index 9a4f9d150..2ce9f3fa5 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java @@ -103,6 +103,7 @@ import app.fedilab.android.databinding.DrawerStatusComposeBinding; import app.fedilab.android.databinding.DrawerStatusSimpleBinding; import app.fedilab.android.databinding.PopupMediaDescriptionBinding; import app.fedilab.android.exception.DBException; +import app.fedilab.android.helper.CustomEmoji; import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.MastodonHelper; import app.fedilab.android.helper.ThemeHelper; @@ -1035,12 +1036,23 @@ public class ComposeAdapter extends RecyclerView.Adapter { + if (!status.emojiFetched) { + status.emojiFetched = true; + holder.binding.statusContent.post(() -> notifyItemChanged(position)); + } + }); holder.binding.statusContent.setText(status.span_content, TextView.BufferType.SPANNABLE); MastodonHelper.loadPPMastodon(holder.binding.avatar, status.account); + CustomEmoji.displayEmoji(context, status.account.emojis, status.account.span_display_name, holder.binding.displayName, status.id, id -> { + if (!status.account.emojiFetched) { + status.account.emojiFetched = true; + holder.binding.statusContent.post(() -> notifyItemChanged(position)); + } + }); holder.binding.displayName.setText(status.account.span_display_name, TextView.BufferType.SPANNABLE); holder.binding.username.setText(String.format("@%s", status.account.acct)); if (status.spoiler_text != null && !status.spoiler_text.trim().isEmpty()) { - holder.binding.spoiler.setVisibility(View.VISIBLE); holder.binding.spoiler.setText(status.span_spoiler_text, TextView.BufferType.SPANNABLE); } else { diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java index c074b16a3..70f2484d7 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java @@ -49,6 +49,7 @@ import app.fedilab.android.client.entities.api.Conversation; import app.fedilab.android.client.entities.api.Status; import app.fedilab.android.databinding.DrawerConversationBinding; import app.fedilab.android.databinding.ThumbnailBinding; +import app.fedilab.android.helper.CustomEmoji; import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.MastodonHelper; @@ -137,6 +138,12 @@ public class ConversationAdapter extends RecyclerView.Adapter { + if (!conversation.last_status.emojiFetched) { + conversation.last_status.emojiFetched = true; + holder.binding.spoiler.post(() -> notifyItemChanged(position)); + } + }); holder.binding.spoiler.setText(conversation.last_status.span_spoiler_text, TextView.BufferType.SPANNABLE); } else { holder.binding.spoiler.setVisibility(View.GONE); @@ -144,6 +151,12 @@ public class ConversationAdapter extends RecyclerView.Adapter { + if (!conversation.last_status.emojiFetched) { + conversation.last_status.emojiFetched = true; + holder.binding.statusContent.post(() -> notifyItemChanged(position)); + } + }); holder.binding.statusContent.setText(conversation.last_status.span_content, TextView.BufferType.SPANNABLE); //--- DATE --- holder.binding.lastMessageDate.setText(Helper.dateDiff(context, conversation.last_status.created_at)); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java index 7a121691c..4cbae4f0c 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java @@ -24,6 +24,7 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.core.app.ActivityOptionsCompat; @@ -42,6 +43,7 @@ import app.fedilab.android.databinding.DrawerFetchMoreBinding; import app.fedilab.android.databinding.DrawerFollowBinding; import app.fedilab.android.databinding.DrawerStatusNotificationBinding; import app.fedilab.android.databinding.NotificationsRelatedAccountsBinding; +import app.fedilab.android.helper.CustomEmoji; import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.MastodonHelper; import app.fedilab.android.viewmodel.mastodon.SearchVM; @@ -120,7 +122,13 @@ public class NotificationAdapter extends RecyclerView.Adapter { + if (!notification.account.emojiFetched) { + notification.account.emojiFetched = true; + holderFollow.binding.displayName.post(() -> notifyItemChanged(position)); + } + }); + holderFollow.binding.displayName.setText(notification.account.span_display_name, TextView.BufferType.SPANNABLE); holderFollow.binding.username.setText(String.format("@%s", notification.account.acct)); if (getItemViewType(position) == TYPE_FOLLOW_REQUEST) { holderFollow.binding.rejectButton.setVisibility(View.VISIBLE); @@ -188,7 +196,13 @@ public class NotificationAdapter extends RecyclerView.Adapter { + if (!notification.account.emojiFetched) { + notification.account.emojiFetched = true; + holderStatus.binding.displayName.post(() -> notifyItemChanged(position)); + } + }); + holderStatus.bindingNotification.status.displayName.setText(title, TextView.BufferType.SPANNABLE); holderStatus.bindingNotification.status.username.setText(String.format("@%s", notification.account.acct)); holderStatus.bindingNotification.containerTransparent.setAlpha(.1f); if (notification.status != null && notification.status.visibility.equalsIgnoreCase("direct")) { @@ -255,7 +269,13 @@ public class NotificationAdapter extends RecyclerView.Adapter { + if (!notification.account.emojiFetched) { + notification.account.emojiFetched = true; + holderStatus.binding.displayName.post(() -> notifyItemChanged(position)); + } + }); + holderStatus.bindingNotification.status.displayName.setText(title, TextView.BufferType.SPANNABLE); holderStatus.bindingNotification.status.username.setText(String.format("@%s", notification.account.acct)); holderStatus.bindingNotification.status.actionButtons.setVisibility(View.GONE); } diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index bbd119d77..631031e29 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -750,6 +750,16 @@ public class StatusAdapter extends RecyclerView.Adapter if (span_display_name == null || span_display_name.toString().trim().length() == 0) { span_display_name = new SpannableString(statusToDeal.account.username); } + + CustomEmoji.displayEmoji(context, statusToDeal.account.emojis, span_display_name, holder.binding.displayName, status.id, id -> { + if (!statusToDeal.account.emojiFetched) { + statusToDeal.account.emojiFetched = true; + if (timelineType == Timeline.TimeLineEnum.UNKNOWN) { + return; + } + holder.binding.statusContent.post(() -> adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, id))); + } + }); holder.binding.displayName.setText(span_display_name, TextView.BufferType.SPANNABLE); if (theme_text_header_1_line != -1) { holder.binding.displayName.setTextColor(theme_text_header_1_line); @@ -815,6 +825,15 @@ public class StatusAdapter extends RecyclerView.Adapter if (expand_cw || expand) { holder.binding.spoilerExpand.setVisibility(View.VISIBLE); holder.binding.spoiler.setVisibility(View.VISIBLE); + CustomEmoji.displayEmoji(context, statusToDeal.emojis, statusToDeal.span_spoiler_text, holder.binding.spoiler, status.id, id -> { + if (!statusToDeal.emojiFetched) { + statusToDeal.emojiFetched = true; + if (timelineType == Timeline.TimeLineEnum.UNKNOWN) { + return; + } + holder.binding.statusContent.post(() -> adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, id))); + } + }); holder.binding.spoiler.setText(statusToDeal.span_spoiler_text, TextView.BufferType.SPANNABLE); statusToDeal.isExpended = true; statusToDeal.isMediaDisplayed = true; @@ -826,6 +845,15 @@ public class StatusAdapter extends RecyclerView.Adapter }); holder.binding.spoilerExpand.setVisibility(View.VISIBLE); holder.binding.spoiler.setVisibility(View.VISIBLE); + CustomEmoji.displayEmoji(context, statusToDeal.emojis, statusToDeal.span_spoiler_text, holder.binding.spoiler, status.id, id -> { + if (!statusToDeal.emojiFetched) { + statusToDeal.emojiFetched = true; + if (timelineType == Timeline.TimeLineEnum.UNKNOWN) { + return; + } + holder.binding.statusContent.post(() -> adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, id))); + } + }); holder.binding.spoiler.setText(statusToDeal.span_spoiler_text, TextView.BufferType.SPANNABLE); } if (statusToDeal.isExpended) { @@ -846,6 +874,15 @@ public class StatusAdapter extends RecyclerView.Adapter if (span_display_name_boost == null || span_display_name_boost.toString().trim().length() == 0) { span_display_name_boost = new SpannableString(status.account.username); } + CustomEmoji.displayEmoji(context, statusToDeal.account.emojis, span_display_name_boost, holder.binding.statusBoosterDisplayName, status.id, id -> { + if (!statusToDeal.account.emojiFetched) { + statusToDeal.account.emojiFetched = true; + if (timelineType == Timeline.TimeLineEnum.UNKNOWN) { + return; + } + holder.binding.statusContent.post(() -> adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, id))); + } + }); holder.binding.statusBoosterDisplayName.setText(span_display_name_boost, TextView.BufferType.SPANNABLE); holder.binding.statusBoosterInfo.setVisibility(View.VISIBLE); holder.binding.boosterDivider.setVisibility(View.VISIBLE); @@ -888,7 +925,7 @@ public class StatusAdapter extends RecyclerView.Adapter holder.binding.statusContent.post(() -> adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, id))); } }); - // CustomEmoji.displayEmoji(statusToDeal.emojis, statusToDeal.span_content, holder.binding.statusContent, null, null); + holder.binding.statusContent.setText(statusToDeal.span_content, TextView.BufferType.SPANNABLE); if (truncate_toots_size > 0) { holder.binding.statusContent.setMaxLines(truncate_toots_size); @@ -920,6 +957,15 @@ public class StatusAdapter extends RecyclerView.Adapter } if (statusToDeal.translationContent != null) { holder.binding.containerTrans.setVisibility(View.VISIBLE); + CustomEmoji.displayEmoji(context, statusToDeal.emojis, statusToDeal.span_translate, holder.binding.statusContentTranslated, status.id, id -> { + if (!statusToDeal.emojiFetched) { + statusToDeal.emojiFetched = true; + if (timelineType == Timeline.TimeLineEnum.UNKNOWN) { + return; + } + holder.binding.statusContent.post(() -> adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, id))); + } + }); holder.binding.statusContentTranslated.setText(statusToDeal.span_translate, TextView.BufferType.SPANNABLE); } else { holder.binding.containerTrans.setVisibility(View.GONE); @@ -1184,6 +1230,15 @@ public class StatusAdapter extends RecyclerView.Adapter pollItemBinding.pollItemPercent.setTextColor(theme_text_color); pollItemBinding.pollItemText.setTextColor(theme_text_color); } + CustomEmoji.displayEmoji(context, statusToDeal.emojis, pollItem.span_title, pollItemBinding.pollItemText, status.id, id -> { + if (!statusToDeal.emojiFetched) { + statusToDeal.emojiFetched = true; + if (timelineType == Timeline.TimeLineEnum.UNKNOWN) { + return; + } + holder.binding.statusContent.post(() -> adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, id))); + } + }); pollItemBinding.pollItemText.setText(pollItem.span_title, TextView.BufferType.SPANNABLE); pollItemBinding.pollItemValue.setProgress((int) value); if (pollItem.votes_count == greaterValue) { @@ -1212,6 +1267,15 @@ public class StatusAdapter extends RecyclerView.Adapter for (Poll.PollItem pollOption : statusToDeal.poll.options) { CheckBox cb = new CheckBox(context); cb.setButtonTintList(ThemeHelper.getButtonColorStateList(context)); + CustomEmoji.displayEmoji(context, statusToDeal.emojis, pollOption.span_title, cb, status.id, id -> { + if (!statusToDeal.emojiFetched) { + statusToDeal.emojiFetched = true; + if (timelineType == Timeline.TimeLineEnum.UNKNOWN) { + return; + } + holder.binding.statusContent.post(() -> adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, id))); + } + }); cb.setText(pollOption.span_title, TextView.BufferType.SPANNABLE); holder.binding.poll.multipleChoice.addView(cb); } @@ -1223,6 +1287,24 @@ public class StatusAdapter extends RecyclerView.Adapter for (Poll.PollItem pollOption : statusToDeal.poll.options) { RadioButton rb = new RadioButton(context); rb.setButtonTintList(ThemeHelper.getButtonColorStateList(context)); + CustomEmoji.displayEmoji(context, statusToDeal.account.emojis, pollOption.span_title, rb, status.id, id -> { + if (!statusToDeal.account.emojiFetched) { + statusToDeal.account.emojiFetched = true; + if (timelineType == Timeline.TimeLineEnum.UNKNOWN) { + return; + } + holder.binding.statusContent.post(() -> adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, id))); + } + }); + CustomEmoji.displayEmoji(context, statusToDeal.emojis, pollOption.span_title, rb, status.id, id -> { + if (!statusToDeal.emojiFetched) { + statusToDeal.emojiFetched = true; + if (timelineType == Timeline.TimeLineEnum.UNKNOWN) { + return; + } + holder.binding.statusContent.post(() -> adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, id))); + } + }); rb.setText(pollOption.span_title, TextView.BufferType.SPANNABLE); holder.binding.poll.singleChoiceRadioGroup.addView(rb); } @@ -1827,6 +1909,15 @@ public class StatusAdapter extends RecyclerView.Adapter .load(status.art_attachment.preview_url) .apply(new RequestOptions().transform(new RoundedCorners((int) Helper.convertDpToPixel(3, context)))) .into(holder.bindingArt.artMedia); + CustomEmoji.displayEmoji(context, status.emojis, status.account.span_display_name, holder.bindingArt.artAcct, status.id, id -> { + if (!status.emojiFetched) { + status.emojiFetched = true; + if (timelineType == Timeline.TimeLineEnum.UNKNOWN) { + return; + } + notifyItemChanged(getPositionAsync(null, statusList, id)); + } + }); holder.bindingArt.artAcct.setText(status.account.span_display_name, TextView.BufferType.SPANNABLE); holder.bindingArt.artUsername.setText(String.format(Locale.getDefault(), "@%s", status.account.acct)); holder.bindingArt.artPp.setOnClickListener(v -> { diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java index 019db2a11..47defbdf5 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java @@ -232,7 +232,7 @@ public class TimelinesVM extends AndroidViewModel { statusList.add(status); } } - statuses.statuses = SpannableHelper.convertNitterStatus(getApplication().getApplicationContext(), statusList); + statuses.statuses = SpannableHelper.convertNitterStatus(statusList); String max_id = publicTlResponse.headers().get("min-id"); statuses.pagination = new Pagination(); statuses.pagination.max_id = max_id;