diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java index 3117b3a94..c7068fe54 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java @@ -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, diff --git a/app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaGridAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaGridAdapter.kt index 613546491..6fc33f23a 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaGridAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaGridAdapter.kt @@ -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 } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/viewthread/edits/ViewEditsAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/viewthread/edits/ViewEditsAdapter.kt index ca01bc6c4..aef461e15 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/viewthread/edits/ViewEditsAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/viewthread/edits/ViewEditsAdapter.kt @@ -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)) } diff --git a/app/src/main/java/com/keylesspalace/tusky/util/BlurhashDrawable.kt b/app/src/main/java/com/keylesspalace/tusky/util/BlurhashDrawable.kt new file mode 100644 index 000000000..4c6fe9a2e --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/util/BlurhashDrawable.kt @@ -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 . */ + +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() + } +} diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ImageLoadingHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/ImageLoadingHelper.kt index 0979f5964..641c78fdd 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ImageLoadingHelper.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/ImageLoadingHelper.kt @@ -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 . */ + @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)) -} diff --git a/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt index c9f213de2..6210bba76 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt @@ -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) }