mirror of
https://github.com/tuskyapp/Tusky
synced 2025-02-04 09:27:33 +01:00
don't load custom emojis in their full size (#4429)
This should save quite some memory, but most importantly it gets rid of this crash: ``` java.lang.RuntimeException: Canvas: trying to draw too large(121969936bytes) bitmap. at android.graphics.RecordingCanvas.throwIfCannotDraw(RecordingCanvas.java:266) at android.graphics.BaseRecordingCanvas.drawBitmap(BaseRecordingCanvas.java:94) at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:549) at com.keylesspalace.tusky.util.EmojiSpan.draw(CustomEmojiHelper.kt:131) ... ```
This commit is contained in:
parent
3736034952
commit
4dec228926
@ -16,7 +16,7 @@
|
|||||||
package com.keylesspalace.tusky.adapter
|
package com.keylesspalace.tusky.adapter
|
||||||
|
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.text.SpannableStringBuilder
|
import android.text.SpannableString
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import android.text.style.StyleSpan
|
import android.text.style.StyleSpan
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@ -67,7 +67,7 @@ class FollowRequestViewHolder(
|
|||||||
val wrappedName = account.name.unicodeWrap()
|
val wrappedName = account.name.unicodeWrap()
|
||||||
val emojifiedName: CharSequence = wrappedName.emojify(
|
val emojifiedName: CharSequence = wrappedName.emojify(
|
||||||
account.emojis,
|
account.emojis,
|
||||||
itemView,
|
binding.displayNameTextView,
|
||||||
animateEmojis
|
animateEmojis
|
||||||
)
|
)
|
||||||
binding.displayNameTextView.text = emojifiedName
|
binding.displayNameTextView.text = emojifiedName
|
||||||
@ -76,9 +76,9 @@ class FollowRequestViewHolder(
|
|||||||
R.string.notification_follow_request_format,
|
R.string.notification_follow_request_format,
|
||||||
wrappedName
|
wrappedName
|
||||||
)
|
)
|
||||||
binding.notificationTextView.text = SpannableStringBuilder(wholeMessage).apply {
|
binding.notificationTextView.text = SpannableString(wholeMessage).apply {
|
||||||
setSpan(StyleSpan(Typeface.BOLD), 0, wrappedName.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
setSpan(StyleSpan(Typeface.BOLD), 0, wrappedName.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
}.emojify(account.emojis, itemView, animateEmojis)
|
}.emojify(account.emojis, binding.notificationTextView, animateEmojis)
|
||||||
}
|
}
|
||||||
binding.notificationTextView.visible(showHeader)
|
binding.notificationTextView.visible(showHeader)
|
||||||
val formattedUsername = itemView.context.getString(
|
val formattedUsername = itemView.context.getString(
|
||||||
|
@ -37,7 +37,6 @@ import com.keylesspalace.tusky.util.emojify
|
|||||||
import com.keylesspalace.tusky.util.parseAsMastodonHtml
|
import com.keylesspalace.tusky.util.parseAsMastodonHtml
|
||||||
import com.keylesspalace.tusky.util.setClickableText
|
import com.keylesspalace.tusky.util.setClickableText
|
||||||
import com.keylesspalace.tusky.util.visible
|
import com.keylesspalace.tusky.util.visible
|
||||||
import java.lang.ref.WeakReference
|
|
||||||
|
|
||||||
interface AnnouncementActionListener : LinkListener {
|
interface AnnouncementActionListener : LinkListener {
|
||||||
fun openReactionPicker(announcementId: String, target: View)
|
fun openReactionPicker(announcementId: String, target: View)
|
||||||
@ -111,7 +110,7 @@ class AnnouncementAdapter(
|
|||||||
// we set the EmojiSpan on a space, because otherwise the Chip won't have the right size
|
// we set the EmojiSpan on a space, because otherwise the Chip won't have the right size
|
||||||
// https://github.com/tuskyapp/Tusky/issues/2308
|
// https://github.com/tuskyapp/Tusky/issues/2308
|
||||||
val spanBuilder = SpannableStringBuilder(" ${reaction.count}")
|
val spanBuilder = SpannableStringBuilder(" ${reaction.count}")
|
||||||
val span = EmojiSpan(WeakReference(this))
|
val span = EmojiSpan(this)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
span.contentDescription = reaction.name
|
span.contentDescription = reaction.name
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,8 @@ class ReportNotificationViewHolder(
|
|||||||
val report = viewData.report!!
|
val report = viewData.report!!
|
||||||
val reporter = viewData.account
|
val reporter = viewData.account
|
||||||
|
|
||||||
val reporterName = reporter.name.unicodeWrap().emojify(reporter.emojis, itemView, statusDisplayOptions.animateEmojis)
|
val reporterName = reporter.name.unicodeWrap().emojify(reporter.emojis, binding.notificationTopText, statusDisplayOptions.animateEmojis)
|
||||||
val reporteeName = report.targetAccount.name.unicodeWrap().emojify(report.targetAccount.emojis, itemView, statusDisplayOptions.animateEmojis)
|
val reporteeName = report.targetAccount.name.unicodeWrap().emojify(report.targetAccount.emojis, binding.notificationTopText, statusDisplayOptions.animateEmojis)
|
||||||
|
|
||||||
binding.notificationTopText.text = itemView.context.getString(R.string.notification_header_report_format, reporterName, reporteeName)
|
binding.notificationTopText.text = itemView.context.getString(R.string.notification_header_report_format, reporterName, reporteeName)
|
||||||
binding.notificationSummary.text = itemView.context.getString(R.string.notification_summary_report_format, getRelativeTimeSpanString(itemView.context, report.createdAt.time, System.currentTimeMillis()), report.statusIds?.size ?: 0)
|
binding.notificationSummary.text = itemView.context.getString(R.string.notification_summary_report_format, getRelativeTimeSpanString(itemView.context, report.createdAt.time, System.currentTimeMillis()), report.statusIds?.size ?: 0)
|
||||||
|
@ -24,10 +24,12 @@ import android.graphics.drawable.Drawable
|
|||||||
import android.text.SpannableStringBuilder
|
import android.text.SpannableStringBuilder
|
||||||
import android.text.style.ReplacementSpan
|
import android.text.style.ReplacementSpan
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.request.target.CustomTarget
|
import com.bumptech.glide.request.target.CustomTarget
|
||||||
import com.bumptech.glide.request.target.Target
|
import com.bumptech.glide.request.target.Target
|
||||||
import com.bumptech.glide.request.transition.Transition
|
import com.bumptech.glide.request.transition.Transition
|
||||||
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.entity.Emoji
|
import com.keylesspalace.tusky.entity.Emoji
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
@ -51,7 +53,7 @@ fun CharSequence.emojify(emojis: List<Emoji>, view: View, animate: Boolean): Cha
|
|||||||
.matcher(this)
|
.matcher(this)
|
||||||
|
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
val span = EmojiSpan(WeakReference(view))
|
val span = EmojiSpan(view)
|
||||||
|
|
||||||
builder.setSpan(span, matcher.start(), matcher.end(), 0)
|
builder.setSpan(span, matcher.start(), matcher.end(), 0)
|
||||||
Glide.with(view)
|
Glide.with(view)
|
||||||
@ -69,7 +71,19 @@ fun CharSequence.emojify(emojis: List<Emoji>, view: View, animate: Boolean): Cha
|
|||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmojiSpan(val viewWeakReference: WeakReference<View>) : ReplacementSpan() {
|
class EmojiSpan(view: View) : ReplacementSpan() {
|
||||||
|
|
||||||
|
private val viewWeakReference = WeakReference(view)
|
||||||
|
|
||||||
|
private val emojiSize: Int = if (view is TextView) {
|
||||||
|
view.paint.textSize
|
||||||
|
} else {
|
||||||
|
// sometimes it is not possible to determine the TextView the emoji will be shown in,
|
||||||
|
// e.g. because it is passed to a library, so we fallback to a size that should be large
|
||||||
|
// enough in most cases
|
||||||
|
view.context.resources.getDimension(R.dimen.fallback_emoji_size)
|
||||||
|
}.times(1.2).toInt()
|
||||||
|
|
||||||
var imageDrawable: Drawable? = null
|
var imageDrawable: Drawable? = null
|
||||||
|
|
||||||
override fun getSize(
|
override fun getSize(
|
||||||
@ -89,7 +103,7 @@ class EmojiSpan(val viewWeakReference: WeakReference<View>) : ReplacementSpan()
|
|||||||
fm.bottom = metrics.bottom
|
fm.bottom = metrics.bottom
|
||||||
}
|
}
|
||||||
|
|
||||||
return (paint.textSize * 1.2).toInt()
|
return emojiSize
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun draw(
|
override fun draw(
|
||||||
@ -134,7 +148,7 @@ class EmojiSpan(val viewWeakReference: WeakReference<View>) : ReplacementSpan()
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getTarget(animate: Boolean): Target<Drawable> {
|
fun getTarget(animate: Boolean): Target<Drawable> {
|
||||||
return object : CustomTarget<Drawable>() {
|
return object : CustomTarget<Drawable>(emojiSize, emojiSize) {
|
||||||
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
||||||
viewWeakReference.get()?.let { view ->
|
viewWeakReference.get()?.let { view ->
|
||||||
if (animate && resource is Animatable) {
|
if (animate && resource is Animatable) {
|
||||||
|
@ -48,7 +48,6 @@ import com.keylesspalace.tusky.R
|
|||||||
import com.keylesspalace.tusky.entity.HashTag
|
import com.keylesspalace.tusky.entity.HashTag
|
||||||
import com.keylesspalace.tusky.entity.Status.Mention
|
import com.keylesspalace.tusky.entity.Status.Mention
|
||||||
import com.keylesspalace.tusky.interfaces.LinkListener
|
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||||
import java.lang.ref.WeakReference
|
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.net.URISyntaxException
|
import java.net.URISyntaxException
|
||||||
|
|
||||||
@ -128,7 +127,7 @@ fun markupHiddenUrls(view: TextView, content: CharSequence): SpannableStringBuil
|
|||||||
|
|
||||||
val linkDrawable = AppCompatResources.getDrawable(view.context, R.drawable.ic_link)!!
|
val linkDrawable = AppCompatResources.getDrawable(view.context, R.drawable.ic_link)!!
|
||||||
// ImageSpan does not always align the icon correctly in the line, let's use our custom emoji span for this
|
// ImageSpan does not always align the icon correctly in the line, let's use our custom emoji span for this
|
||||||
val linkDrawableSpan = EmojiSpan(WeakReference(view))
|
val linkDrawableSpan = EmojiSpan(view)
|
||||||
linkDrawableSpan.imageDrawable = linkDrawable
|
linkDrawableSpan.imageDrawable = linkDrawable
|
||||||
|
|
||||||
val placeholderIndex = replacementText.indexOf("🔗")
|
val placeholderIndex = replacementText.indexOf("🔗")
|
||||||
|
@ -75,4 +75,6 @@
|
|||||||
|
|
||||||
<dimen name="account_swiperefresh_distance">64dp</dimen>
|
<dimen name="account_swiperefresh_distance">64dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="fallback_emoji_size">16sp</dimen>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user