Show tooltips instead of Toasts when long-pressing attachment images (#4382)

- Use `TooltipCompat.setTooltipText()` instead of setting an
`OnLongClickListener` showing a Toast, to show the attachment
description. This method will display native tooltips on API 26+, and
set an `OnLongClickListener` on older versions to display a special
Toast anchored to the view. In both cases this provides a better user
experience.
- Simplify `Attachment.getFormattedDescription()` by using Kotlin's
`Duration`. Since it's an inline class, no extra memory will be
allocated on the heap. Also, ensure that the calculation of minutes and
hours use the rounded number of seconds instead of the non-rounded one.
This commit is contained in:
Christophe Beyls 2024-05-03 13:21:02 +02:00 committed by GitHub
parent e96ca01dec
commit 76c6ec5510
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 21 additions and 31 deletions

View File

@ -17,12 +17,12 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.PopupMenu;
import androidx.appcompat.widget.TooltipCompat;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import androidx.core.text.HtmlCompat;
@ -74,7 +74,6 @@ import java.text.NumberFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import at.connyduck.sparkbutton.SparkButton;
import at.connyduck.sparkbutton.helpers.Utils;
@ -541,7 +540,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
imageView.setForeground(null);
}
setAttachmentClickListener(imageView, listener, i, attachment, true);
final CharSequence formattedDescription = AttachmentHelper.getFormattedDescription(attachment, imageView.getContext());
setAttachmentClickListener(imageView, listener, i, formattedDescription, true);
if (sensitive) {
sensitiveMediaWarning.setText(R.string.post_sensitive_media_title);
@ -613,15 +613,15 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
int drawableId = getLabelIcon(attachments.get(0).getType());
mediaLabel.setCompoundDrawablesWithIntrinsicBounds(drawableId, 0, 0, 0);
setAttachmentClickListener(mediaLabel, listener, i, attachment, false);
setAttachmentClickListener(mediaLabel, listener, i, mediaDescriptions[i], false);
} else {
mediaLabel.setVisibility(View.GONE);
}
}
}
private void setAttachmentClickListener(View view, @NonNull StatusActionListener listener,
int index, Attachment attachment, boolean animateTransition) {
private void setAttachmentClickListener(@NonNull View view, @NonNull StatusActionListener listener,
int index, CharSequence description, boolean animateTransition) {
view.setOnClickListener(v -> {
int position = getBindingAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
@ -632,11 +632,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
}
}
});
view.setOnLongClickListener(v -> {
CharSequence description = AttachmentHelper.getFormattedDescription(attachment, view.getContext());
Toast.makeText(view.getContext(), description, Toast.LENGTH_LONG).show();
return true;
});
TooltipCompat.setTooltipText(view, description);
}
protected void hideSensitiveMediaWarning() {

View File

@ -5,8 +5,8 @@ import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.content.res.AppCompatResources
import androidx.appcompat.widget.TooltipCompat
import androidx.core.view.setPadding
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
@ -141,11 +141,7 @@ class AccountMediaGridAdapter(
onAttachmentClickListener(item, imageView)
}
holder.binding.root.setOnLongClickListener { view ->
val description = item.attachment.getFormattedDescription(view.context)
Toast.makeText(view.context, description, Toast.LENGTH_LONG).show()
true
}
TooltipCompat.setTooltipText(holder.binding.root, imageView.contentDescription)
}
}
}

View File

@ -6,24 +6,22 @@ import android.content.Context
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.entity.Attachment
import kotlin.math.roundToInt
import kotlin.time.Duration.Companion.seconds
fun Attachment.getFormattedDescription(context: Context): CharSequence {
var duration = ""
if (meta?.duration != null && meta.duration > 0) {
duration = formatDuration(meta.duration.toDouble()) + " "
}
return if (description.isNullOrEmpty()) {
duration + context.getString(R.string.description_post_media_no_description_placeholder)
val durationInSeconds = meta?.duration ?: 0f
val duration = if (durationInSeconds > 0f) {
durationInSeconds.roundToInt().seconds.toComponents { hours, minutes, seconds, _ ->
"%d:%02d:%02d ".format(hours, minutes, seconds)
}
} else {
duration + description
""
}
return duration + if (description.isNullOrEmpty()) {
context.getString(R.string.description_post_media_no_description_placeholder)
} else {
description
}
}
private fun formatDuration(durationInSeconds: Double): String {
val seconds = durationInSeconds.roundToInt() % 60
val minutes = durationInSeconds.toInt() % 3600 / 60
val hours = durationInSeconds.toInt() / 3600
return "%d:%02d:%02d".format(hours, minutes, seconds)
}
fun List<Attachment>.aspectRatios(): List<Double> {