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.
This commit is contained in:
Nik Clayton 2024-02-20 16:20:34 +01:00 committed by GitHub
parent 8293e90b73
commit 941f4677eb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 56 additions and 67 deletions

View File

@ -216,17 +216,6 @@
column="5"/> column="5"/>
</issue> </issue>
<issue
id="MissingQuantity"
message="For locale &quot;ru&quot; (Russian) the following quantities should also be defined: `few` (e.g. &quot;из 2 книг за 2 дня&quot;), `many` (e.g. &quot;из 5 книг за 5 дней&quot;), `one` (e.g. &quot;из 1 книги за 1 день&quot;)"
errorLine1=" &lt;plurals name=&quot;hint_describe_for_visually_impaired&quot;>"
errorLine2=" ^">
<location
file="src/main/res/values-ru/strings.xml"
line="279"
column="5"/>
</issue>
<issue <issue
id="MissingQuantity" id="MissingQuantity"
message="For locale &quot;hi&quot; (Hindi) the following quantity should also be defined: `one` (e.g. &quot;1 घंटा&quot;)" message="For locale &quot;hi&quot; (Hindi) the following quantity should also be defined: `one` (e.g. &quot;1 घंटा&quot;)"

View File

@ -897,14 +897,14 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(i
} }
companion object { companion object {
/**
* @return True if all [attachments] are previewable.
*
* @see Attachment.isPreviewable
*/
@JvmStatic @JvmStatic
protected fun hasPreviewableAttachment(attachments: List<Attachment>): Boolean { protected fun hasPreviewableAttachment(attachments: List<Attachment>): Boolean {
for (attachment in attachments) { return attachments.all { it.isPreviewable() }
if (attachment.type == Attachment.Type.UNKNOWN) return false
if (attachment.meta?.original?.width == null && attachment.meta?.small?.width == null) return false
}
return true
} }
private fun getReblogDescription(context: Context, status: IStatusViewData): CharSequence { private fun getReblogDescription(context: Context, status: IStatusViewData): CharSequence {

View File

@ -7,19 +7,18 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
import androidx.core.view.setPadding
import androidx.paging.PagingDataAdapter import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import app.pachli.R import app.pachli.R
import app.pachli.adapter.isPlayable
import app.pachli.core.activity.decodeBlurHash import app.pachli.core.activity.decodeBlurHash
import app.pachli.core.common.extensions.hide
import app.pachli.core.common.extensions.show 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.navigation.AttachmentViewData
import app.pachli.core.network.model.Attachment
import app.pachli.databinding.ItemAccountMediaBinding import app.pachli.databinding.ItemAccountMediaBinding
import app.pachli.util.BindingHolder import app.pachli.util.BindingHolder
import app.pachli.util.getFormattedDescription import app.pachli.util.getFormattedDescription
import app.pachli.util.iconResource
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.google.android.material.color.MaterialColors import com.google.android.material.color.MaterialColors
import java.util.Random 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 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 mediaHiddenDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_hide_media_24dp)
private val itemBgBaseHSV = FloatArray(3) private val itemBgBaseHSV = FloatArray(3)
@ -57,59 +56,53 @@ class AccountMediaGridAdapter(
override fun onBindViewHolder(holder: BindingHolder<ItemAccountMediaBinding>, position: Int) { override fun onBindViewHolder(holder: BindingHolder<ItemAccountMediaBinding>, position: Int) {
val context = holder.binding.root.context val context = holder.binding.root.context
getItem(position)?.let { item ->
getItem(position)?.let { item ->
val imageView = holder.binding.accountMediaImageView val imageView = holder.binding.accountMediaImageView
val overlay = holder.binding.accountMediaImageViewOverlay val overlay = holder.binding.accountMediaImageViewOverlay
val blurhash = item.attachment.blurhash val placeholder = item.attachment.blurhash?.let {
val placeholder = if (useBlurhash && blurhash != null) { if (useBlurhash) decodeBlurHash(context, it) else null
decodeBlurHash(context, blurhash)
} else {
null
} }
if (item.attachment.type == Attachment.Type.AUDIO) { when {
overlay.hide() item.sensitive && !item.isRevealed -> {
imageView.setPadding(context.resources.getDimensionPixelSize(DR.dimen.profile_media_audio_icon_padding))
Glide.with(imageView)
.load(R.drawable.ic_music_box_preview_24dp)
.centerInside()
.into(imageView)
imageView.contentDescription = item.attachment.getFormattedDescription(context)
} else if (item.sensitive && !item.isRevealed) {
overlay.show()
overlay.setImageDrawable(mediaHiddenDrawable)
imageView.setPadding(0)
Glide.with(imageView)
.load(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.show()
overlay.setImageDrawable(videoIndicator) overlay.setImageDrawable(mediaHiddenDrawable)
} else {
overlay.hide() Glide.with(imageView)
.load(placeholder)
.centerInside()
.into(imageView)
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) Glide.with(imageView)
.asBitmap() .asBitmap()
.load(item.attachment.previewUrl) .load(item.attachment.previewUrl)
.placeholder(placeholder) .placeholder(placeholder)
.centerInside() .centerInside()
.into(imageView) .into(imageView)
imageView.contentDescription = item.attachment.getFormattedDescription(context) imageView.contentDescription = item.attachment.getFormattedDescription(context)
}
else -> {
if (item.attachment.type.isPlayable()) overlay.setImageDrawable(playableIcon)
overlay.visible(item.attachment.type.isPlayable())
Glide.with(imageView)
.load(item.attachment.iconResource())
.centerInside()
.into(imageView)
imageView.contentDescription = item.attachment.getFormattedDescription(context)
}
} }
holder.binding.root.setOnClickListener { holder.binding.root.setOnClickListener {
@ -118,7 +111,7 @@ class AccountMediaGridAdapter(
holder.binding.root.setOnLongClickListener { view -> holder.binding.root.setOnLongClickListener { view ->
val description = item.attachment.getFormattedDescription(view.context) 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 true
} }
} }

View File

@ -63,8 +63,6 @@
<dimen name="profile_media_spacing">3dp</dimen> <dimen name="profile_media_spacing">3dp</dimen>
<dimen name="profile_media_audio_icon_padding">16dp</dimen>
<dimen name="preview_image_spacing">4dp</dimen> <dimen name="preview_image_spacing">4dp</dimen>
<dimen name="graph_line_thickness">1dp</dimen> <dimen name="graph_line_thickness">1dp</dimen>

View File

@ -103,4 +103,13 @@ data class Attachment(
return (width / height).toDouble() 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)
}
} }