CustomEmojiHelper: rewrite to Kotlin

main
Alibek Omarov 5 years ago
parent 2ee70be3e4
commit 86b57cd1ef
  1. 6
      app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt
  2. 4
      app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt
  3. 2
      app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
  4. 4
      app/src/main/java/com/keylesspalace/tusky/adapter/AccountFieldAdapter.kt
  5. 2
      app/src/main/java/com/keylesspalace/tusky/adapter/AccountSelectionAdapter.kt
  6. 4
      app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java
  7. 4
      app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.java
  8. 4
      app/src/main/java/com/keylesspalace/tusky/adapter/ComposeAutoCompleteAdapter.java
  9. 2
      app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestViewHolder.kt
  10. 4
      app/src/main/java/com/keylesspalace/tusky/adapter/MutedStatusViewHolder.java
  11. 4
      app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java
  12. 16
      app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java
  13. 7
      app/src/main/java/com/keylesspalace/tusky/adapter/PollAdapter.kt
  14. 6
      app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java
  15. 4
      app/src/main/java/com/keylesspalace/tusky/components/report/adapter/StatusViewHolder.kt
  16. 58
      app/src/main/java/com/keylesspalace/tusky/util/CustomEmojiHelper.kt
  17. 6
      app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.java
  18. 2
      app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt

@ -364,9 +364,9 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
val usernameFormatted = getString(R.string.status_username_format, account.username) val usernameFormatted = getString(R.string.status_username_format, account.username)
accountUsernameTextView.text = usernameFormatted accountUsernameTextView.text = usernameFormatted
accountDisplayNameTextView.text = emojifyString(account.name, account.emojis, accountDisplayNameTextView) accountDisplayNameTextView.text = account.name.emojify(account.emojis, accountDisplayNameTextView, true)
val emojifiedNote = emojifyText(account.note, account.emojis, accountNoteTextView) val emojifiedNote = account.note.emojify(account.emojis, accountNoteTextView)
LinkHelper.setClickableText(accountNoteTextView, emojifiedNote, null, this) LinkHelper.setClickableText(accountNoteTextView, emojifiedNote, null, this)
// accountFieldAdapter.fields = account.fields ?: emptyList() // accountFieldAdapter.fields = account.fields ?: emptyList()
@ -438,7 +438,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
private fun updateToolbar() { private fun updateToolbar() {
loadedAccount?.let { account -> loadedAccount?.let { account ->
val emojifiedName = emojifyString(account.name, account.emojis, accountToolbar, true) val emojifiedName = account.name.emojify(account.emojis, accountToolbar)
try { try {
supportActionBar?.title = EmojiCompat.get().process(emojifiedName) supportActionBar?.title = EmojiCompat.get().process(emojifiedName)

@ -209,7 +209,7 @@ class AccountsInListFragment : DialogFragment(), Injectable {
} }
fun bind(account: Account) { fun bind(account: Account) {
displayNameTextView.text = emojifyString(account.name, account.emojis, displayNameTextView) displayNameTextView.text = account.name.emojify(account.emojis, displayNameTextView)
usernameTextView.text = account.username usernameTextView.text = account.username
loadAvatar(account.avatar, avatar, radius, animateAvatar) loadAvatar(account.avatar, avatar, radius, animateAvatar)
} }
@ -252,7 +252,7 @@ class AccountsInListFragment : DialogFragment(), Injectable {
override val containerView = itemView override val containerView = itemView
fun bind(account: Account, inAList: Boolean) { fun bind(account: Account, inAList: Boolean) {
displayNameTextView.text = emojifyString(account.name, account.emojis, displayNameTextView) displayNameTextView.text = account.name.emojify(account.emojis, displayNameTextView)
usernameTextView.text = account.username usernameTextView.text = account.username
loadAvatar(account.avatar, avatar, radius, animateAvatar) loadAvatar(account.avatar, avatar, radius, animateAvatar)

@ -592,7 +592,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
private fun updateProfiles() { private fun updateProfiles() {
val profiles: MutableList<IProfile> = accountManager.getAllAccountsOrderedByActive().map { acc -> val profiles: MutableList<IProfile> = accountManager.getAllAccountsOrderedByActive().map { acc ->
val emojifiedName = EmojiCompat.get().process(emojifyString(acc.displayName, acc.emojis, header)) val emojifiedName = EmojiCompat.get().process(acc.displayName.emojify(acc.emojis, header))
ProfileDrawerItem().apply { ProfileDrawerItem().apply {
isSelected = acc.isActive isSelected = acc.isActive

@ -55,10 +55,10 @@ class AccountFieldAdapter(private val linkListener: LinkListener) : RecyclerView
viewHolder.valueTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_check_circle, 0) viewHolder.valueTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_check_circle, 0)
} else { } else {
val field = proofOrField.asRight() val field = proofOrField.asRight()
val emojifiedName = emojifyString(field.name, emojis, viewHolder.nameTextView) val emojifiedName = field.name.emojify(emojis, viewHolder.nameTextView)
viewHolder.nameTextView.text = emojifiedName viewHolder.nameTextView.text = emojifiedName
val emojifiedValue = emojifyText(field.value, emojis, viewHolder.valueTextView) val emojifiedValue = field.value.emojify(emojis, viewHolder.valueTextView)
LinkHelper.setClickableText(viewHolder.valueTextView, emojifiedValue, null, linkListener) LinkHelper.setClickableText(viewHolder.valueTextView, emojifiedValue, null, linkListener)
if(field.verifiedAt != null) { if(field.verifiedAt != null) {

@ -42,7 +42,7 @@ class AccountSelectionAdapter(context: Context) : ArrayAdapter<AccountEntity>(co
val displayName = view.display_name val displayName = view.display_name
val avatar = view.avatar val avatar = view.avatar
username.text = account.fullName username.text = account.fullName
displayName.text = emojifyString(account.displayName, account.emojis, displayName) displayName.text = account.displayName.emojify(account.emojis, displayName)
val avatarRadius = avatar.context.resources.getDimensionPixelSize(R.dimen.avatar_radius_42dp) val avatarRadius = avatar.context.resources.getDimensionPixelSize(R.dimen.avatar_radius_42dp)
val animateAvatar = PreferenceManager.getDefaultSharedPreferences(avatar.context) val animateAvatar = PreferenceManager.getDefaultSharedPreferences(avatar.context)

@ -12,7 +12,7 @@ import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.interfaces.AccountActionListener; import com.keylesspalace.tusky.interfaces.AccountActionListener;
import com.keylesspalace.tusky.interfaces.LinkListener; import com.keylesspalace.tusky.interfaces.LinkListener;
import com.keylesspalace.tusky.util.CustomEmojiHelperKt; import com.keylesspalace.tusky.util.CustomEmojiHelper;
import com.keylesspalace.tusky.util.ImageLoadingHelper; import com.keylesspalace.tusky.util.ImageLoadingHelper;
public class AccountViewHolder extends RecyclerView.ViewHolder { public class AccountViewHolder extends RecyclerView.ViewHolder {
@ -40,7 +40,7 @@ public class AccountViewHolder extends RecyclerView.ViewHolder {
String format = username.getContext().getString(R.string.status_username_format); String format = username.getContext().getString(R.string.status_username_format);
String formattedUsername = String.format(format, account.getUsername()); String formattedUsername = String.format(format, account.getUsername());
username.setText(formattedUsername); username.setText(formattedUsername);
CharSequence emojifiedName = CustomEmojiHelperKt.emojifyString(account.getName(), account.getEmojis(), displayName); CharSequence emojifiedName = CustomEmojiHelper.emojify(account.getName(), account.getEmojis(), displayName);
displayName.setText(emojifiedName); displayName.setText(emojifiedName);
int avatarRadius = avatar.getContext().getResources() int avatarRadius = avatar.getContext().getResources()
.getDimensionPixelSize(R.dimen.avatar_radius_48dp); .getDimensionPixelSize(R.dimen.avatar_radius_48dp);

@ -29,7 +29,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.interfaces.AccountActionListener; import com.keylesspalace.tusky.interfaces.AccountActionListener;
import com.keylesspalace.tusky.util.CustomEmojiHelperKt; import com.keylesspalace.tusky.util.CustomEmojiHelper;
import com.keylesspalace.tusky.util.ImageLoadingHelper; import com.keylesspalace.tusky.util.ImageLoadingHelper;
public class BlocksAdapter extends AccountAdapter { public class BlocksAdapter extends AccountAdapter {
@ -86,7 +86,7 @@ public class BlocksAdapter extends AccountAdapter {
void setupWithAccount(Account account) { void setupWithAccount(Account account) {
id = account.getId(); id = account.getId();
CharSequence emojifiedName = CustomEmojiHelperKt.emojifyString(account.getName(), account.getEmojis(), displayName); CharSequence emojifiedName = CustomEmojiHelper.emojify(account.getName(), account.getEmojis(), displayName);
displayName.setText(emojifiedName); displayName.setText(emojifiedName);
String format = username.getContext().getString(R.string.status_username_format); String format = username.getContext().getString(R.string.status_username_format);
String formattedUsername = String.format(format, account.getUsername()); String formattedUsername = String.format(format, account.getUsername());

@ -31,7 +31,7 @@ import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.entity.Emoji; import com.keylesspalace.tusky.entity.Emoji;
import com.keylesspalace.tusky.entity.HashTag; import com.keylesspalace.tusky.entity.HashTag;
import com.keylesspalace.tusky.util.CustomEmojiHelperKt; import com.keylesspalace.tusky.util.CustomEmojiHelper;
import com.keylesspalace.tusky.util.ImageLoadingHelper; import com.keylesspalace.tusky.util.ImageLoadingHelper;
import java.util.ArrayList; import java.util.ArrayList;
@ -146,7 +146,7 @@ public class ComposeAutoCompleteAdapter extends BaseAdapter
account.getUsername() account.getUsername()
); );
accountViewHolder.username.setText(formattedUsername); accountViewHolder.username.setText(formattedUsername);
CharSequence emojifiedName = CustomEmojiHelperKt.emojifyString(account.getName(), CharSequence emojifiedName = CustomEmojiHelper.emojify(account.getName(),
account.getEmojis(), accountViewHolder.displayName); account.getEmojis(), accountViewHolder.displayName);
accountViewHolder.displayName.setText(emojifiedName); accountViewHolder.displayName.setText(emojifiedName);

@ -18,7 +18,7 @@ internal class FollowRequestViewHolder(itemView: View, private val showHeader: B
fun setupWithAccount(account: Account, formatter: BidiFormatter?) { fun setupWithAccount(account: Account, formatter: BidiFormatter?) {
id = account.id id = account.id
val wrappedName = formatter?.unicodeWrap(account.name) ?: account.name val wrappedName = formatter?.unicodeWrap(account.name) ?: account.name
val emojifiedName: CharSequence = emojifyString(wrappedName, account.emojis, itemView, true) val emojifiedName: CharSequence = wrappedName.emojify(account.emojis, itemView, true)
itemView.displayNameTextView.text = emojifiedName itemView.displayNameTextView.text = emojifiedName
if (showHeader) { if (showHeader) {
itemView.notificationTextView?.text = itemView.context.getString(R.string.notification_follow_request_format, emojifiedName) itemView.notificationTextView?.text = itemView.context.getString(R.string.notification_follow_request_format, emojifiedName)

@ -13,7 +13,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Emoji; import com.keylesspalace.tusky.entity.Emoji;
import com.keylesspalace.tusky.interfaces.StatusActionListener; import com.keylesspalace.tusky.interfaces.StatusActionListener;
import com.keylesspalace.tusky.util.CustomEmojiHelperKt; import com.keylesspalace.tusky.util.CustomEmojiHelper;
import com.keylesspalace.tusky.util.StatusDisplayOptions; import com.keylesspalace.tusky.util.StatusDisplayOptions;
import com.keylesspalace.tusky.util.TimestampUtils; import com.keylesspalace.tusky.util.TimestampUtils;
import com.keylesspalace.tusky.viewdata.StatusViewData; import com.keylesspalace.tusky.viewdata.StatusViewData;
@ -48,7 +48,7 @@ public class MutedStatusViewHolder extends RecyclerView.ViewHolder {
} }
protected void setDisplayName(String name, List<Emoji> customEmojis) { protected void setDisplayName(String name, List<Emoji> customEmojis) {
CharSequence emojifiedName = CustomEmojiHelperKt.emojifyString(name, customEmojis, displayName, true); CharSequence emojifiedName = CustomEmojiHelper.emojify(name, customEmojis, displayName, true);
displayName.setText(emojifiedName); displayName.setText(emojifiedName);
} }

@ -14,7 +14,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.interfaces.AccountActionListener; import com.keylesspalace.tusky.interfaces.AccountActionListener;
import com.keylesspalace.tusky.util.CustomEmojiHelperKt; import com.keylesspalace.tusky.util.CustomEmojiHelper;
import com.keylesspalace.tusky.util.ImageLoadingHelper; import com.keylesspalace.tusky.util.ImageLoadingHelper;
public class MutesAdapter extends AccountAdapter { public class MutesAdapter extends AccountAdapter {
@ -71,7 +71,7 @@ public class MutesAdapter extends AccountAdapter {
void setupWithAccount(Account account) { void setupWithAccount(Account account) {
id = account.getId(); id = account.getId();
CharSequence emojifiedName = CustomEmojiHelperKt.emojifyString(account.getName(), account.getEmojis(), displayName); CharSequence emojifiedName = CustomEmojiHelper.emojify(account.getName(), account.getEmojis(), displayName);
displayName.setText(emojifiedName); displayName.setText(emojifiedName);
String format = username.getContext().getString(R.string.status_username_format); String format = username.getContext().getString(R.string.status_username_format);
String formattedUsername = String.format(format, account.getUsername()); String formattedUsername = String.format(format, account.getUsername());

@ -46,7 +46,7 @@ import com.keylesspalace.tusky.interfaces.AccountActionListener;
import com.keylesspalace.tusky.interfaces.LinkListener; import com.keylesspalace.tusky.interfaces.LinkListener;
import com.keylesspalace.tusky.interfaces.StatusActionListener; import com.keylesspalace.tusky.interfaces.StatusActionListener;
import com.keylesspalace.tusky.util.CardViewMode; import com.keylesspalace.tusky.util.CardViewMode;
import com.keylesspalace.tusky.util.CustomEmojiHelperKt; import com.keylesspalace.tusky.util.CustomEmojiHelper;
import com.keylesspalace.tusky.util.ImageLoadingHelper; import com.keylesspalace.tusky.util.ImageLoadingHelper;
import com.keylesspalace.tusky.util.LinkHelper; import com.keylesspalace.tusky.util.LinkHelper;
import com.keylesspalace.tusky.util.SmartLengthInputFilter; import com.keylesspalace.tusky.util.SmartLengthInputFilter;
@ -347,13 +347,13 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
String format = context.getString(R.string.notification_follow_format); String format = context.getString(R.string.notification_follow_format);
String wrappedDisplayName = bidiFormatter.unicodeWrap(account.getName()); String wrappedDisplayName = bidiFormatter.unicodeWrap(account.getName());
String wholeMessage = String.format(format, wrappedDisplayName); String wholeMessage = String.format(format, wrappedDisplayName);
CharSequence emojifiedMessage = CustomEmojiHelperKt.emojifyString(wholeMessage, account.getEmojis(), message, true); CharSequence emojifiedMessage = CustomEmojiHelper.emojify(wholeMessage, account.getEmojis(), message, true);
message.setText(emojifiedMessage); message.setText(emojifiedMessage);
String username = context.getString(R.string.status_username_format, account.getUsername()); String username = context.getString(R.string.status_username_format, account.getUsername());
usernameView.setText(username); usernameView.setText(username);
CharSequence emojifiedDisplayName = CustomEmojiHelperKt.emojifyString(wrappedDisplayName, account.getEmojis(), usernameView, true); CharSequence emojifiedDisplayName = CustomEmojiHelper.emojify(wrappedDisplayName, account.getEmojis(), usernameView, true);
displayNameView.setText(emojifiedDisplayName); displayNameView.setText(emojifiedDisplayName);
@ -429,7 +429,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
} }
private void setDisplayName(String name, List<Emoji> emojis) { private void setDisplayName(String name, List<Emoji> emojis) {
CharSequence emojifiedName = CustomEmojiHelperKt.emojifyString(name, emojis, displayName, true); CharSequence emojifiedName = CustomEmojiHelper.emojify(name, emojis, displayName, true);
displayName.setText(emojifiedName); displayName.setText(emojifiedName);
} }
@ -526,7 +526,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
final SpannableStringBuilder str = new SpannableStringBuilder(wholeMessage); final SpannableStringBuilder str = new SpannableStringBuilder(wholeMessage);
str.setSpan(new StyleSpan(Typeface.BOLD), 0, displayName.length(), str.setSpan(new StyleSpan(Typeface.BOLD), 0, displayName.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
CharSequence emojifiedText = CustomEmojiHelperKt.emojifyText(str, notificationViewData.getAccount().getEmojis(), message); CharSequence emojifiedText = CustomEmojiHelper.emojify(str, notificationViewData.getAccount().getEmojis(), message);
message.setText(emojifiedText); message.setText(emojifiedText);
if (statusViewData != null) { if (statusViewData != null) {
@ -621,11 +621,11 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
statusContent.setFilters(NO_INPUT_FILTER); statusContent.setFilters(NO_INPUT_FILTER);
} }
Spanned emojifiedText = CustomEmojiHelperKt.emojifyText(content, emojis, statusContent); CharSequence emojifiedText = CustomEmojiHelper.emojify(content, emojis, statusContent);
LinkHelper.setClickableText(statusContent, emojifiedText, statusViewData.getMentions(), listener); LinkHelper.setClickableText(statusContent, emojifiedText, statusViewData.getMentions(), listener);
Spanned emojifiedContentWarning = CharSequence emojifiedContentWarning =
CustomEmojiHelperKt.emojifyString(statusViewData.getSpoilerText(), statusViewData.getStatusEmojis(), contentWarningDescriptionTextView); CustomEmojiHelper.emojify(statusViewData.getSpoilerText(), statusViewData.getStatusEmojis(), contentWarningDescriptionTextView);
contentWarningDescriptionTextView.setText(emojifiedContentWarning); contentWarningDescriptionTextView.setText(emojifiedContentWarning);
} }
} }

@ -70,7 +70,8 @@ class PollAdapter: RecyclerView.Adapter<PollViewHolder>() {
when(mode) { when(mode) {
RESULT -> { RESULT -> {
val percent = calculatePercent(option.votesCount, voteCount) val percent = calculatePercent(option.votesCount, voteCount)
val emojifiedPollOptionText = emojifyText(buildDescription(option.title, percent, holder.resultTextView.context), emojis, holder.resultTextView) val emojifiedPollOptionText = buildDescription(option.title, percent, holder.resultTextView.context)
.emojify(emojis, holder.resultTextView)
holder.resultTextView.text = EmojiCompat.get().process(emojifiedPollOptionText) holder.resultTextView.text = EmojiCompat.get().process(emojifiedPollOptionText)
val level = percent * 100 val level = percent * 100
@ -79,7 +80,7 @@ class PollAdapter: RecyclerView.Adapter<PollViewHolder>() {
} }
SINGLE -> { SINGLE -> {
val emojifiedPollOptionText = emojifyString(option.title, emojis, holder.radioButton) val emojifiedPollOptionText = option.title.emojify(emojis, holder.radioButton)
holder.radioButton.text = EmojiCompat.get().process(emojifiedPollOptionText) holder.radioButton.text = EmojiCompat.get().process(emojifiedPollOptionText)
holder.radioButton.isChecked = option.selected holder.radioButton.isChecked = option.selected
holder.radioButton.setOnClickListener { holder.radioButton.setOnClickListener {
@ -90,7 +91,7 @@ class PollAdapter: RecyclerView.Adapter<PollViewHolder>() {
} }
} }
MULTIPLE -> { MULTIPLE -> {
val emojifiedPollOptionText = emojifyString(option.title, emojis, holder.checkBox) val emojifiedPollOptionText = option.title.emojify(emojis, holder.checkBox)
holder.checkBox.text = EmojiCompat.get().process(emojifiedPollOptionText) holder.checkBox.text = EmojiCompat.get().process(emojifiedPollOptionText)
holder.checkBox.isChecked = option.selected holder.checkBox.isChecked = option.selected
holder.checkBox.setOnCheckedChangeListener { _, isChecked -> holder.checkBox.setOnCheckedChangeListener { _, isChecked ->

@ -195,7 +195,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
protected abstract int getMediaPreviewHeight(Context context); protected abstract int getMediaPreviewHeight(Context context);
protected void setDisplayName(String name, List<Emoji> customEmojis) { protected void setDisplayName(String name, List<Emoji> customEmojis) {
CharSequence emojifiedName = CustomEmojiHelperKt.emojifyString(name, customEmojis, displayName, true); CharSequence emojifiedName = CustomEmojiHelper.emojify(name, customEmojis, displayName, true);
displayName.setText(emojifiedName); displayName.setText(emojifiedName);
} }
@ -219,7 +219,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
final StatusActionListener listener) { final StatusActionListener listener) {
boolean sensitive = !TextUtils.isEmpty(spoilerText); boolean sensitive = !TextUtils.isEmpty(spoilerText);
if (sensitive) { if (sensitive) {
CharSequence emojiSpoiler = CustomEmojiHelperKt.emojifyString(spoilerText, emojis, contentWarningDescription); CharSequence emojiSpoiler = CustomEmojiHelper.emojify(spoilerText, emojis, contentWarningDescription);
contentWarningDescription.setText(emojiSpoiler); contentWarningDescription.setText(emojiSpoiler);
contentWarningDescription.setVisibility(View.VISIBLE); contentWarningDescription.setVisibility(View.VISIBLE);
contentWarningButton.setVisibility(View.VISIBLE); contentWarningButton.setVisibility(View.VISIBLE);
@ -258,7 +258,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
StatusDisplayOptions statusDisplayOptions, StatusDisplayOptions statusDisplayOptions,
final StatusActionListener listener) { final StatusActionListener listener) {
if (expanded) { if (expanded) {
Spanned emojifiedText = CustomEmojiHelperKt.emojifyText(content, emojis, this.content); CharSequence emojifiedText = CustomEmojiHelper.emojify(content, emojis, this.content);
LinkHelper.setClickableText(this.content, emojifiedText, mentions, listener); LinkHelper.setClickableText(this.content, emojifiedText, mentions, listener);
for (int i = 0; i < mediaLabels.length; ++i) { for (int i = 0; i < mediaLabels.length; ++i) {
updateMediaLabel(i, sensitive, expanded); updateMediaLabel(i, sensitive, expanded);

@ -89,7 +89,7 @@ class StatusViewHolder(
itemView.statusContentWarningButton.hide() itemView.statusContentWarningButton.hide()
itemView.statusContentWarningDescription.hide() itemView.statusContentWarningDescription.hide()
} else { } else {
val emojiSpoiler = emojifyString(status.spoilerText, status.emojis, itemView.statusContentWarningDescription) val emojiSpoiler = status.spoilerText.emojify(status.emojis, itemView.statusContentWarningDescription)
itemView.statusContentWarningDescription.text = emojiSpoiler itemView.statusContentWarningDescription.text = emojiSpoiler
itemView.statusContentWarningDescription.show() itemView.statusContentWarningDescription.show()
itemView.statusContentWarningButton.show() itemView.statusContentWarningButton.show()
@ -122,7 +122,7 @@ class StatusViewHolder(
emojis: List<Emoji>, emojis: List<Emoji>,
listener: LinkListener) { listener: LinkListener) {
if (expanded) { if (expanded) {
val emojifiedText = emojifyText(content, emojis, itemView.statusContent) val emojifiedText = content.emojify(emojis, itemView.statusContent)
LinkHelper.setClickableText(itemView.statusContent, emojifiedText, mentions, listener) LinkHelper.setClickableText(itemView.statusContent, emojifiedText, mentions, listener)
} else { } else {
LinkHelper.setClickableMentions(itemView.statusContent, mentions, listener) LinkHelper.setClickableMentions(itemView.statusContent, mentions, listener)

@ -1,4 +1,4 @@
/* Copyright 2017 Andrew Dawson /* Copyright 2020 Tusky Contributors
* *
* This file is a part of Tusky. * This file is a part of Tusky.
* *
@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not, * You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
@file:JvmName("CustomEmojiHelper")
package com.keylesspalace.tusky.util package com.keylesspalace.tusky.util
import android.graphics.Bitmap import android.graphics.Bitmap
@ -21,8 +22,6 @@ import android.graphics.Paint
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.SpannedString
import android.text.style.ReplacementSpan import android.text.style.ReplacementSpan
import android.view.View import android.view.View
@ -43,50 +42,41 @@ import androidx.preference.PreferenceManager
* @param view a reference to the a view the emojis will be shown in (should be the TextView, but parents of the TextView are also acceptable) * @param view a reference to the a view the emojis will be shown in (should be the TextView, but parents of the TextView are also acceptable)
* @return the text with the shortcodes replaced by EmojiSpans * @return the text with the shortcodes replaced by EmojiSpans
*/ */
fun emojifyText(text: Spanned, emojis: List<Emoji>?, view: View, forceSmallEmoji: Boolean) : Spanned { fun CharSequence.emojify(emojis: List<Emoji>?, view: View, forceSmallEmoji: Boolean) : CharSequence {
if(emojis.isNullOrEmpty())
return this
val builder = SpannableStringBuilder.valueOf(this)
val pm = PreferenceManager.getDefaultSharedPreferences(view.context) val pm = PreferenceManager.getDefaultSharedPreferences(view.context)
val smallEmojis = forceSmallEmoji || !pm.getBoolean("bigEmojis", true) val smallEmojis = forceSmallEmoji || !pm.getBoolean("bigEmojis", true)
// val animatedEmojis = pm.getBoolean("animateEmojis", false) // val animatedEmojis = pm.getBoolean("animateEmojis", false)
if (emojis != null && emojis.isNotEmpty()) { emojis.forEach { (shortcode, url) ->
val builder = SpannableStringBuilder(text) val matcher = Pattern.compile(":$shortcode:", Pattern.LITERAL)
for (emoji in emojis) { .matcher(this)
val pattern = StringBuilder(":").append(emoji.shortcode).append(":")
val matcher = Pattern.compile(pattern.toString(), Pattern.LITERAL)
.matcher(text)
while(matcher.find()) { while(matcher.find()) {
val span = if(smallEmojis) { val span = if(smallEmojis) {
SmallEmojiSpan(WeakReference<View>(view)) SmallEmojiSpan(WeakReference<View>(view))
} else { } else {
EmojiSpan(WeakReference<View>(view)) EmojiSpan(WeakReference<View>(view))
} }
builder.setSpan(span, matcher.start(), matcher.end(), 0); builder.setSpan(span, matcher.start(), matcher.end(), 0);
Glide.with(view) Glide.with(view)
.asBitmap() .asBitmap()
.load(emoji.url) .load(url)
.into(span.getTarget()) .into(span.getTarget())
} }
} }
return builder return builder
}
return text
} }
fun emojifyText(text: Spanned, emojis: List<Emoji>?, view: View) : Spanned { fun CharSequence.emojify(emojis: List<Emoji>?, view: View) : CharSequence {
return emojifyText(text, emojis, view, false) return this.emojify(emojis, view, false)
} }
fun emojifyString(string: String, emojis: List<Emoji>?, view: View, forceSmallEmoji: Boolean) : Spanned { open class EmojiSpan(val viewWeakReference: WeakReference<View>) : ReplacementSpan() {
return emojifyText(SpannedString(string), emojis, view, forceSmallEmoji)
}
fun emojifyString(string: String, emojis: List<Emoji>?, view: View) : Spanned {
return emojifyString(string, emojis, view, false)
}
public open class EmojiSpan(val viewWeakReference: WeakReference<View>) : ReplacementSpan() {
var imageDrawable: Drawable? = null var imageDrawable: Drawable? = null
override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: Paint.FontMetricsInt?) : Int { override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: Paint.FontMetricsInt?) : Int {
@ -104,27 +94,25 @@ public open class EmojiSpan(val viewWeakReference: WeakReference<View>) : Replac
} }
override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) { override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
if (imageDrawable == null) imageDrawable?.let { drawable ->
return
canvas.save() canvas.save()
val emojiSize = getSize(paint, text, start, end, null) val emojiSize = getSize(paint, text, start, end, null)
imageDrawable!!.setBounds(0, 0, emojiSize, emojiSize) drawable.setBounds(0, 0, emojiSize, emojiSize)
var transY = bottom - imageDrawable!!.bounds.bottom var transY = bottom - drawable.bounds.bottom
transY -= paint.fontMetricsInt.descent / 2; transY -= paint.fontMetricsInt.descent / 2;
canvas.translate(x, transY.toFloat()) canvas.translate(x, transY.toFloat())
imageDrawable!!.draw(canvas) drawable.draw(canvas)
canvas.restore() canvas.restore()
} }
}
fun getTarget(): Target<Bitmap> { fun getTarget(): Target<Bitmap> {
return object : CustomTarget<Bitmap>() { return object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) { override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
val view = viewWeakReference.get() viewWeakReference.get()?.let { view ->
if (view != null) {
imageDrawable = BitmapDrawable(view.context.resources, resource) imageDrawable = BitmapDrawable(view.context.resources, resource)
view.invalidate() view.invalidate()
} }
@ -135,7 +123,7 @@ public open class EmojiSpan(val viewWeakReference: WeakReference<View>) : Replac
} }
} }
public class SmallEmojiSpan(viewWeakReference: WeakReference<View>) class SmallEmojiSpan(viewWeakReference: WeakReference<View>)
: EmojiSpan(viewWeakReference) { : EmojiSpan(viewWeakReference) {
override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int { override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int {
if (fm != null) { if (fm != null) {

@ -72,10 +72,10 @@ public class LinkHelper {
* @param mentions any '@' mentions which are known to be in the content * @param mentions any '@' mentions which are known to be in the content
* @param listener to notify about particular spans that are clicked * @param listener to notify about particular spans that are clicked
*/ */
public static void setClickableText(TextView view, Spanned content, public static void setClickableText(TextView view, CharSequence content,
@Nullable Status.Mention[] mentions, final LinkListener listener) { @Nullable Status.Mention[] mentions, final LinkListener listener) {
SpannableStringBuilder builder = new SpannableStringBuilder(content); SpannableStringBuilder builder = SpannableStringBuilder.valueOf(content);
URLSpan[] urlSpans = content.getSpans(0, content.length(), URLSpan.class); URLSpan[] urlSpans = builder.getSpans(0, content.length(), URLSpan.class);
for (URLSpan span : urlSpans) { for (URLSpan span : urlSpans) {
int start = builder.getSpanStart(span); int start = builder.getSpanStart(span);
int end = builder.getSpanEnd(span); int end = builder.getSpanEnd(span);

@ -298,7 +298,7 @@ class StatusViewHelper(private val itemView: View) {
val percent = calculatePercent(options[i].votesCount, poll.votesCount) val percent = calculatePercent(options[i].votesCount, poll.votesCount)
val pollOptionText = buildDescription(options[i].title, percent, pollResults[i].context) val pollOptionText = buildDescription(options[i].title, percent, pollResults[i].context)
pollResults[i].text = emojifyText(pollOptionText, emojis, pollResults[i]) pollResults[i].text = pollOptionText.emojify(emojis, pollResults[i])
pollResults[i].visibility = View.VISIBLE pollResults[i].visibility = View.VISIBLE
val level = percent * 100 val level = percent * 100

Loading…
Cancel
Save