From 941f4677ebba390115d3b19676a3d13b41724adc Mon Sep 17 00:00:00 2001 From: Nik Clayton Date: Tue, 20 Feb 2024 16:20:34 +0100 Subject: [PATCH] fix: Show previews for playable audio media from accounts (#460) Previous code showed a generic placeholder for audio media on the account's "Media" tab. Fix this so the preview image is shown (if it's available). - Move the "is this attachment previewable?" code to `Attachment` so it can be reused here. - Restructure the logic in `AccountMediaGridAdapter` to use the new `isPreviewable()` method when deciding whether to show a preview. - Attachments have dedicated placeholder drawables, use those when the preview is not available. --- app/lint-baseline.xml | 11 --- .../pachli/adapter/StatusBaseViewHolder.kt | 12 +-- .../account/media/AccountMediaGridAdapter.kt | 81 +++++++++---------- .../src/main/res/values/dimens.xml | 2 - .../pachli/core/network/model/Attachment.kt | 9 +++ 5 files changed, 52 insertions(+), 63 deletions(-) diff --git a/app/lint-baseline.xml b/app/lint-baseline.xml index 9b7487bb6..89bcf046a 100644 --- a/app/lint-baseline.xml +++ b/app/lint-baseline.xml @@ -216,17 +216,6 @@ column="5"/> - - - - protected constructor(i } companion object { + /** + * @return True if all [attachments] are previewable. + * + * @see Attachment.isPreviewable + */ @JvmStatic protected fun hasPreviewableAttachment(attachments: List): Boolean { - for (attachment in attachments) { - if (attachment.type == Attachment.Type.UNKNOWN) return false - - if (attachment.meta?.original?.width == null && attachment.meta?.small?.width == null) return false - } - return true + return attachments.all { it.isPreviewable() } } private fun getReblogDescription(context: Context, status: IStatusViewData): CharSequence { diff --git a/app/src/main/java/app/pachli/components/account/media/AccountMediaGridAdapter.kt b/app/src/main/java/app/pachli/components/account/media/AccountMediaGridAdapter.kt index 4069dc77d..2940b82b3 100644 --- a/app/src/main/java/app/pachli/components/account/media/AccountMediaGridAdapter.kt +++ b/app/src/main/java/app/pachli/components/account/media/AccountMediaGridAdapter.kt @@ -7,19 +7,18 @@ import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.appcompat.content.res.AppCompatResources -import androidx.core.view.setPadding import androidx.paging.PagingDataAdapter import androidx.recyclerview.widget.DiffUtil import app.pachli.R +import app.pachli.adapter.isPlayable import app.pachli.core.activity.decodeBlurHash -import app.pachli.core.common.extensions.hide import app.pachli.core.common.extensions.show -import app.pachli.core.designsystem.R as DR +import app.pachli.core.common.extensions.visible import app.pachli.core.navigation.AttachmentViewData -import app.pachli.core.network.model.Attachment import app.pachli.databinding.ItemAccountMediaBinding import app.pachli.util.BindingHolder import app.pachli.util.getFormattedDescription +import app.pachli.util.iconResource import com.bumptech.glide.Glide import com.google.android.material.color.MaterialColors import java.util.Random @@ -41,7 +40,7 @@ class AccountMediaGridAdapter( ) { private val baseItemBackgroundColor = MaterialColors.getColor(context, com.google.android.material.R.attr.colorSurface, Color.BLACK) - private val videoIndicator = AppCompatResources.getDrawable(context, R.drawable.ic_play_indicator) + private val playableIcon = AppCompatResources.getDrawable(context, R.drawable.ic_play_indicator) private val mediaHiddenDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_hide_media_24dp) private val itemBgBaseHSV = FloatArray(3) @@ -57,59 +56,53 @@ class AccountMediaGridAdapter( override fun onBindViewHolder(holder: BindingHolder, position: Int) { val context = holder.binding.root.context - getItem(position)?.let { item -> + getItem(position)?.let { item -> val imageView = holder.binding.accountMediaImageView val overlay = holder.binding.accountMediaImageViewOverlay - val blurhash = item.attachment.blurhash - val placeholder = if (useBlurhash && blurhash != null) { - decodeBlurHash(context, blurhash) - } else { - null + val placeholder = item.attachment.blurhash?.let { + if (useBlurhash) decodeBlurHash(context, it) else null } - if (item.attachment.type == Attachment.Type.AUDIO) { - overlay.hide() - - imageView.setPadding(context.resources.getDimensionPixelSize(DR.dimen.profile_media_audio_icon_padding)) + when { + item.sensitive && !item.isRevealed -> { + overlay.show() + overlay.setImageDrawable(mediaHiddenDrawable) - Glide.with(imageView) - .load(R.drawable.ic_music_box_preview_24dp) - .centerInside() - .into(imageView) + Glide.with(imageView) + .load(placeholder) + .centerInside() + .into(imageView) - imageView.contentDescription = item.attachment.getFormattedDescription(context) - } else if (item.sensitive && !item.isRevealed) { - overlay.show() - overlay.setImageDrawable(mediaHiddenDrawable) + imageView.contentDescription = context.getString(R.string.post_media_hidden_title) + } - imageView.setPadding(0) + item.attachment.isPreviewable() -> { + if (item.attachment.type.isPlayable()) overlay.setImageDrawable(playableIcon) + overlay.visible(item.attachment.type.isPlayable()) - Glide.with(imageView) - .load(placeholder) - .centerInside() - .into(imageView) + Glide.with(imageView) + .asBitmap() + .load(item.attachment.previewUrl) + .placeholder(placeholder) + .centerInside() + .into(imageView) - imageView.contentDescription = imageView.context.getString(R.string.post_media_hidden_title) - } else { - if (item.attachment.type == Attachment.Type.VIDEO || item.attachment.type == Attachment.Type.GIFV) { - overlay.show() - overlay.setImageDrawable(videoIndicator) - } else { - overlay.hide() + imageView.contentDescription = item.attachment.getFormattedDescription(context) } - imageView.setPadding(0) + else -> { + if (item.attachment.type.isPlayable()) overlay.setImageDrawable(playableIcon) + overlay.visible(item.attachment.type.isPlayable()) - Glide.with(imageView) - .asBitmap() - .load(item.attachment.previewUrl) - .placeholder(placeholder) - .centerInside() - .into(imageView) + Glide.with(imageView) + .load(item.attachment.iconResource()) + .centerInside() + .into(imageView) - imageView.contentDescription = item.attachment.getFormattedDescription(context) + imageView.contentDescription = item.attachment.getFormattedDescription(context) + } } holder.binding.root.setOnClickListener { @@ -118,7 +111,7 @@ class AccountMediaGridAdapter( holder.binding.root.setOnLongClickListener { view -> val description = item.attachment.getFormattedDescription(view.context) - Toast.makeText(view.context, description, Toast.LENGTH_LONG).show() + Toast.makeText(context, description, Toast.LENGTH_LONG).show() true } } diff --git a/core/designsystem/src/main/res/values/dimens.xml b/core/designsystem/src/main/res/values/dimens.xml index b7dbc6060..0eb525e35 100644 --- a/core/designsystem/src/main/res/values/dimens.xml +++ b/core/designsystem/src/main/res/values/dimens.xml @@ -63,8 +63,6 @@ 3dp - 16dp - 4dp 1dp diff --git a/core/network/src/main/kotlin/app/pachli/core/network/model/Attachment.kt b/core/network/src/main/kotlin/app/pachli/core/network/model/Attachment.kt index d71fc5fb3..84db4e753 100644 --- a/core/network/src/main/kotlin/app/pachli/core/network/model/Attachment.kt +++ b/core/network/src/main/kotlin/app/pachli/core/network/model/Attachment.kt @@ -103,4 +103,13 @@ data class Attachment( return (width / height).toDouble() } } + + /** + * @return True if this attachment can be previewed. A previewable attachment + * must be a known type and have a non-null width for the preview image. + */ + fun isPreviewable(): Boolean { + if (type == Type.UNKNOWN) return false + return !(meta?.original?.width == null && meta?.small?.width == null) + } }