fix images sometimes flickering when interacting with a post (#4971)
Glide compares the previous load with the current load, and if they are identical, does basically nothing. Thats what we want, because otherwise it flickers when the requested image is not in the memory cache. The problem is, we decode the blurhash we use as placeholder everytime. And the BitmapDrawables we get don't have a proper equals implementation. So Glide is like: Aha, different placeholder, better load again -> Flicker I added a BlurhashDrawable with custom equals/hashCode and now the flickering is gone.
This commit is contained in:
parent
e1c319b6e3
commit
3c728d9bea
6 changed files with 63 additions and 14 deletions
|
|
@ -54,6 +54,7 @@ import com.keylesspalace.tusky.entity.Translation;
|
|||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.util.AbsoluteTimeFormatter;
|
||||
import com.keylesspalace.tusky.util.AttachmentHelper;
|
||||
import com.keylesspalace.tusky.util.BlurhashDrawable;
|
||||
import com.keylesspalace.tusky.util.CardViewMode;
|
||||
import com.keylesspalace.tusky.util.CompositeWithOpaqueBackground;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
|
|
@ -473,7 +474,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
|
||||
private BitmapDrawable decodeBlurHash(String blurhash) {
|
||||
return ImageLoadingHelper.decodeBlurHash(this.avatar.getContext(), blurhash);
|
||||
return new BlurhashDrawable(this.avatar.getContext(), blurhash);
|
||||
}
|
||||
|
||||
private void loadImage(MediaPreviewImageView imageView,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import com.keylesspalace.tusky.R
|
|||
import com.keylesspalace.tusky.databinding.ItemAccountMediaBinding
|
||||
import com.keylesspalace.tusky.entity.Attachment
|
||||
import com.keylesspalace.tusky.util.BindingHolder
|
||||
import com.keylesspalace.tusky.util.decodeBlurHash
|
||||
import com.keylesspalace.tusky.util.BlurhashDrawable
|
||||
import com.keylesspalace.tusky.util.getFormattedDescription
|
||||
import com.keylesspalace.tusky.util.hide
|
||||
import com.keylesspalace.tusky.util.show
|
||||
|
|
@ -86,7 +86,7 @@ class AccountMediaGridAdapter(
|
|||
|
||||
val blurhash = item.attachment.blurhash
|
||||
val placeholder = if (useBlurhash && blurhash != null) {
|
||||
decodeBlurHash(context, blurhash)
|
||||
BlurhashDrawable(context, blurhash)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ import com.keylesspalace.tusky.entity.StatusEdit
|
|||
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||
import com.keylesspalace.tusky.util.AbsoluteTimeFormatter
|
||||
import com.keylesspalace.tusky.util.BindingHolder
|
||||
import com.keylesspalace.tusky.util.BlurhashDrawable
|
||||
import com.keylesspalace.tusky.util.TuskyTagHandler
|
||||
import com.keylesspalace.tusky.util.aspectRatios
|
||||
import com.keylesspalace.tusky.util.decodeBlurHash
|
||||
import com.keylesspalace.tusky.util.emojify
|
||||
import com.keylesspalace.tusky.util.hide
|
||||
import com.keylesspalace.tusky.util.parseAsMastodonHtml
|
||||
|
|
@ -186,7 +186,7 @@ class ViewEditsAdapter(
|
|||
val blurhash = attachment.blurhash
|
||||
|
||||
val placeholder: Drawable = if (blurhash != null && useBlurhash) {
|
||||
decodeBlurHash(context, blurhash)
|
||||
BlurhashDrawable(context, blurhash)
|
||||
} else {
|
||||
ColorDrawable(MaterialColors.getColor(imageView, R.attr.colorBackgroundAccent))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
/* Copyright 2025 Tusky Contributors
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.util
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
|
||||
/**
|
||||
* Drawable to display blurhashes with custom equals and hashCode implementation.
|
||||
* This is so Glide does not flicker unnecessarily when it is used with blurhashes as placeholder.
|
||||
*/
|
||||
class BlurhashDrawable(
|
||||
context: Context,
|
||||
val blurhash: String
|
||||
) : BitmapDrawable(
|
||||
context.resources,
|
||||
BlurHashDecoder.decode(blurhash, 32, 32, 1f)
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return (other as? BlurhashDrawable)?.blurhash == blurhash
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return blurhash.hashCode()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,23 @@
|
|||
/* Copyright 2025 Tusky Contributors
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
@file:JvmName("ImageLoadingHelper")
|
||||
|
||||
package com.keylesspalace.tusky.util
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.Px
|
||||
import com.bumptech.glide.Glide
|
||||
|
|
@ -52,7 +65,3 @@ fun loadAvatar(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun decodeBlurHash(context: Context, blurhash: String): BitmapDrawable {
|
||||
return BitmapDrawable(context.resources, BlurHashDecoder.decode(blurhash, 32, 32, 1f))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ class StatusViewHelper(private val itemView: View) {
|
|||
.into(mediaPreviews[i])
|
||||
} else {
|
||||
val placeholder = if (attachment.blurhash != null) {
|
||||
decodeBlurHash(context, attachment.blurhash)
|
||||
BlurhashDrawable(context, attachment.blurhash)
|
||||
} else {
|
||||
mediaPreviewUnloaded
|
||||
}
|
||||
|
|
@ -143,8 +143,8 @@ class StatusViewHelper(private val itemView: View) {
|
|||
} else {
|
||||
mediaPreviews[i].removeFocalPoint()
|
||||
if (statusDisplayOptions.useBlurhash && attachment.blurhash != null) {
|
||||
val blurhashBitmap = decodeBlurHash(context, attachment.blurhash)
|
||||
mediaPreviews[i].setImageDrawable(blurhashBitmap)
|
||||
val blurhashDrawable = BlurhashDrawable(context, attachment.blurhash)
|
||||
mediaPreviews[i].setImageDrawable(blurhashDrawable)
|
||||
} else {
|
||||
mediaPreviews[i].setImageDrawable(mediaPreviewUnloaded)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue