mirror of
https://github.com/tuskyapp/Tusky
synced 2025-01-31 18:45:05 +01:00
Add option to not crop image previews (#2832)
* Don't crop image previews with aspects between 2:1 & 1:2 Fixes #1995 * Custom media preview layout for handling various aspect ratios
This commit is contained in:
parent
6b95790457
commit
cc790ccf69
@ -1,5 +1,7 @@
|
|||||||
package com.keylesspalace.tusky.adapter;
|
package com.keylesspalace.tusky.adapter;
|
||||||
|
|
||||||
|
import static com.keylesspalace.tusky.viewdata.PollViewDataKt.buildDescription;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
@ -23,6 +25,7 @@ import androidx.appcompat.app.AlertDialog;
|
|||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.core.text.HtmlCompat;
|
import androidx.core.text.HtmlCompat;
|
||||||
|
import androidx.core.view.ViewKt;
|
||||||
import androidx.recyclerview.widget.DefaultItemAnimator;
|
import androidx.recyclerview.widget.DefaultItemAnimator;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
@ -53,6 +56,7 @@ import com.keylesspalace.tusky.util.StatusDisplayOptions;
|
|||||||
import com.keylesspalace.tusky.util.ThemeUtils;
|
import com.keylesspalace.tusky.util.ThemeUtils;
|
||||||
import com.keylesspalace.tusky.util.TimestampUtils;
|
import com.keylesspalace.tusky.util.TimestampUtils;
|
||||||
import com.keylesspalace.tusky.view.MediaPreviewImageView;
|
import com.keylesspalace.tusky.view.MediaPreviewImageView;
|
||||||
|
import com.keylesspalace.tusky.view.MediaPreviewLayout;
|
||||||
import com.keylesspalace.tusky.viewdata.PollOptionViewData;
|
import com.keylesspalace.tusky.viewdata.PollOptionViewData;
|
||||||
import com.keylesspalace.tusky.viewdata.PollViewData;
|
import com.keylesspalace.tusky.viewdata.PollViewData;
|
||||||
import com.keylesspalace.tusky.viewdata.PollViewDataKt;
|
import com.keylesspalace.tusky.viewdata.PollViewDataKt;
|
||||||
@ -66,12 +70,11 @@ import at.connyduck.sparkbutton.SparkButton;
|
|||||||
import at.connyduck.sparkbutton.helpers.Utils;
|
import at.connyduck.sparkbutton.helpers.Utils;
|
||||||
import kotlin.collections.CollectionsKt;
|
import kotlin.collections.CollectionsKt;
|
||||||
|
|
||||||
import static com.keylesspalace.tusky.viewdata.PollViewDataKt.buildDescription;
|
|
||||||
|
|
||||||
public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
public static class Key {
|
public static class Key {
|
||||||
public static final String KEY_CREATED = "created";
|
public static final String KEY_CREATED = "created";
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextView displayName;
|
private TextView displayName;
|
||||||
private TextView username;
|
private TextView username;
|
||||||
private ImageButton replyButton;
|
private ImageButton replyButton;
|
||||||
@ -81,8 +84,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||||||
private SparkButton bookmarkButton;
|
private SparkButton bookmarkButton;
|
||||||
private ImageButton moreButton;
|
private ImageButton moreButton;
|
||||||
private ConstraintLayout mediaContainer;
|
private ConstraintLayout mediaContainer;
|
||||||
protected MediaPreviewImageView[] mediaPreviews;
|
protected MediaPreviewLayout mediaPreview;
|
||||||
private ImageView[] mediaOverlays;
|
|
||||||
private TextView sensitiveMediaWarning;
|
private TextView sensitiveMediaWarning;
|
||||||
private View sensitiveMediaShow;
|
private View sensitiveMediaShow;
|
||||||
protected TextView[] mediaLabels;
|
protected TextView[] mediaLabels;
|
||||||
@ -132,19 +134,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||||||
|
|
||||||
mediaContainer = itemView.findViewById(R.id.status_media_preview_container);
|
mediaContainer = itemView.findViewById(R.id.status_media_preview_container);
|
||||||
mediaContainer.setClipToOutline(true);
|
mediaContainer.setClipToOutline(true);
|
||||||
|
mediaPreview = itemView.findViewById(R.id.status_media_preview);
|
||||||
|
|
||||||
mediaPreviews = new MediaPreviewImageView[]{
|
|
||||||
itemView.findViewById(R.id.status_media_preview_0),
|
|
||||||
itemView.findViewById(R.id.status_media_preview_1),
|
|
||||||
itemView.findViewById(R.id.status_media_preview_2),
|
|
||||||
itemView.findViewById(R.id.status_media_preview_3)
|
|
||||||
};
|
|
||||||
mediaOverlays = new ImageView[]{
|
|
||||||
itemView.findViewById(R.id.status_media_overlay_0),
|
|
||||||
itemView.findViewById(R.id.status_media_overlay_1),
|
|
||||||
itemView.findViewById(R.id.status_media_overlay_2),
|
|
||||||
itemView.findViewById(R.id.status_media_overlay_3)
|
|
||||||
};
|
|
||||||
sensitiveMediaWarning = itemView.findViewById(R.id.status_sensitive_media_warning);
|
sensitiveMediaWarning = itemView.findViewById(R.id.status_sensitive_media_warning);
|
||||||
sensitiveMediaShow = itemView.findViewById(R.id.status_sensitive_media_button);
|
sensitiveMediaShow = itemView.findViewById(R.id.status_sensitive_media_button);
|
||||||
mediaLabels = new TextView[]{
|
mediaLabels = new TextView[]{
|
||||||
@ -181,8 +172,6 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||||||
mediaPreviewUnloaded = new ColorDrawable(ThemeUtils.getColor(itemView.getContext(), R.attr.colorBackgroundAccent));
|
mediaPreviewUnloaded = new ColorDrawable(ThemeUtils.getColor(itemView.getContext(), R.attr.colorBackgroundAccent));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract int getMediaPreviewHeight(Context context);
|
|
||||||
|
|
||||||
protected void setDisplayName(String name, List<Emoji> customEmojis, StatusDisplayOptions statusDisplayOptions) {
|
protected void setDisplayName(String name, List<Emoji> customEmojis, StatusDisplayOptions statusDisplayOptions) {
|
||||||
CharSequence emojifiedName = CustomEmojiHelper.emojify(
|
CharSequence emojifiedName = CustomEmojiHelper.emojify(
|
||||||
name, customEmojis, displayName, statusDisplayOptions.animateEmojis()
|
name, customEmojis, displayName, statusDisplayOptions.animateEmojis()
|
||||||
@ -420,64 +409,51 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||||||
|
|
||||||
Drawable placeholder = blurhash != null ? decodeBlurHash(blurhash) : mediaPreviewUnloaded;
|
Drawable placeholder = blurhash != null ? decodeBlurHash(blurhash) : mediaPreviewUnloaded;
|
||||||
|
|
||||||
if (TextUtils.isEmpty(previewUrl)) {
|
ViewKt.doOnLayout(imageView, view -> {
|
||||||
imageView.removeFocalPoint();
|
if (TextUtils.isEmpty(previewUrl)) {
|
||||||
|
|
||||||
Glide.with(imageView)
|
|
||||||
.load(placeholder)
|
|
||||||
.centerInside()
|
|
||||||
.into(imageView);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Focus focus = meta != null ? meta.getFocus() : null;
|
|
||||||
|
|
||||||
if (focus != null) { // If there is a focal point for this attachment:
|
|
||||||
imageView.setFocalPoint(focus);
|
|
||||||
|
|
||||||
Glide.with(imageView)
|
|
||||||
.load(previewUrl)
|
|
||||||
.placeholder(placeholder)
|
|
||||||
.centerInside()
|
|
||||||
.addListener(imageView)
|
|
||||||
.into(imageView);
|
|
||||||
} else {
|
|
||||||
imageView.removeFocalPoint();
|
imageView.removeFocalPoint();
|
||||||
|
|
||||||
Glide.with(imageView)
|
Glide.with(imageView)
|
||||||
.load(previewUrl)
|
.load(placeholder)
|
||||||
.placeholder(placeholder)
|
|
||||||
.centerInside()
|
.centerInside()
|
||||||
.into(imageView);
|
.into(imageView);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Focus focus = meta != null ? meta.getFocus() : null;
|
||||||
|
|
||||||
|
if (focus != null) { // If there is a focal point for this attachment:
|
||||||
|
imageView.setFocalPoint(focus);
|
||||||
|
|
||||||
|
Glide.with(imageView)
|
||||||
|
.load(previewUrl)
|
||||||
|
.placeholder(placeholder)
|
||||||
|
.centerInside()
|
||||||
|
.addListener(imageView)
|
||||||
|
.into(imageView);
|
||||||
|
} else {
|
||||||
|
imageView.removeFocalPoint();
|
||||||
|
|
||||||
|
Glide.with(imageView)
|
||||||
|
.load(previewUrl)
|
||||||
|
.placeholder(placeholder)
|
||||||
|
.centerInside()
|
||||||
|
.into(imageView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setMediaPreviews(final List<Attachment> attachments, boolean sensitive,
|
protected void setMediaPreviews(final List<Attachment> attachments, boolean sensitive,
|
||||||
final StatusActionListener listener, boolean showingContent,
|
final StatusActionListener listener, boolean showingContent,
|
||||||
boolean useBlurhash) {
|
boolean useBlurhash) {
|
||||||
Context context = itemView.getContext();
|
|
||||||
final int n = Math.min(attachments.size(), Status.MAX_MEDIA_ATTACHMENTS);
|
|
||||||
|
|
||||||
|
mediaPreview.setAspectRatios(AttachmentHelper.aspectRatios(attachments));
|
||||||
|
|
||||||
final int mediaPreviewHeight = getMediaPreviewHeight(context);
|
mediaPreview.forEachIndexed((i, imageView) -> {
|
||||||
|
|
||||||
if (n <= 2) {
|
|
||||||
mediaPreviews[0].getLayoutParams().height = mediaPreviewHeight * 2;
|
|
||||||
mediaPreviews[1].getLayoutParams().height = mediaPreviewHeight * 2;
|
|
||||||
} else {
|
|
||||||
mediaPreviews[0].getLayoutParams().height = mediaPreviewHeight;
|
|
||||||
mediaPreviews[1].getLayoutParams().height = mediaPreviewHeight;
|
|
||||||
mediaPreviews[2].getLayoutParams().height = mediaPreviewHeight;
|
|
||||||
mediaPreviews[3].getLayoutParams().height = mediaPreviewHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
Attachment attachment = attachments.get(i);
|
Attachment attachment = attachments.get(i);
|
||||||
String previewUrl = attachment.getPreviewUrl();
|
String previewUrl = attachment.getPreviewUrl();
|
||||||
String description = attachment.getDescription();
|
String description = attachment.getDescription();
|
||||||
MediaPreviewImageView imageView = mediaPreviews[i];
|
|
||||||
|
|
||||||
imageView.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(description)) {
|
if (TextUtils.isEmpty(description)) {
|
||||||
imageView.setContentDescription(imageView.getContext()
|
imageView.setContentDescription(imageView.getContext()
|
||||||
@ -495,42 +471,38 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||||||
|
|
||||||
final Attachment.Type type = attachment.getType();
|
final Attachment.Type type = attachment.getType();
|
||||||
if (showingContent && (type == Attachment.Type.VIDEO || type == Attachment.Type.GIFV)) {
|
if (showingContent && (type == Attachment.Type.VIDEO || type == Attachment.Type.GIFV)) {
|
||||||
mediaOverlays[i].setVisibility(View.VISIBLE);
|
imageView.setForeground(ContextCompat.getDrawable(itemView.getContext(), R.drawable.play_indicator_overlay));
|
||||||
} else {
|
} else {
|
||||||
mediaOverlays[i].setVisibility(View.GONE);
|
imageView.setForeground(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
setAttachmentClickListener(imageView, listener, i, attachment, true);
|
setAttachmentClickListener(imageView, listener, i, attachment, true);
|
||||||
}
|
|
||||||
|
|
||||||
if (sensitive) {
|
if (sensitive) {
|
||||||
sensitiveMediaWarning.setText(R.string.post_sensitive_media_title);
|
sensitiveMediaWarning.setText(R.string.post_sensitive_media_title);
|
||||||
} else {
|
} else {
|
||||||
sensitiveMediaWarning.setText(R.string.post_media_hidden_title);
|
sensitiveMediaWarning.setText(R.string.post_media_hidden_title);
|
||||||
}
|
|
||||||
|
|
||||||
sensitiveMediaWarning.setVisibility(showingContent ? View.GONE : View.VISIBLE);
|
|
||||||
sensitiveMediaShow.setVisibility(showingContent ? View.VISIBLE : View.GONE);
|
|
||||||
sensitiveMediaShow.setOnClickListener(v -> {
|
|
||||||
if (getBindingAdapterPosition() != RecyclerView.NO_POSITION) {
|
|
||||||
listener.onContentHiddenChange(false, getBindingAdapterPosition());
|
|
||||||
}
|
}
|
||||||
v.setVisibility(View.GONE);
|
|
||||||
sensitiveMediaWarning.setVisibility(View.VISIBLE);
|
|
||||||
});
|
|
||||||
sensitiveMediaWarning.setOnClickListener(v -> {
|
|
||||||
if (getBindingAdapterPosition() != RecyclerView.NO_POSITION) {
|
|
||||||
listener.onContentHiddenChange(true, getBindingAdapterPosition());
|
|
||||||
}
|
|
||||||
v.setVisibility(View.GONE);
|
|
||||||
sensitiveMediaShow.setVisibility(View.VISIBLE);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
sensitiveMediaWarning.setVisibility(showingContent ? View.GONE : View.VISIBLE);
|
||||||
|
sensitiveMediaShow.setVisibility(showingContent ? View.VISIBLE : View.GONE);
|
||||||
|
sensitiveMediaShow.setOnClickListener(v -> {
|
||||||
|
if (getBindingAdapterPosition() != RecyclerView.NO_POSITION) {
|
||||||
|
listener.onContentHiddenChange(false, getBindingAdapterPosition());
|
||||||
|
}
|
||||||
|
v.setVisibility(View.GONE);
|
||||||
|
sensitiveMediaWarning.setVisibility(View.VISIBLE);
|
||||||
|
});
|
||||||
|
sensitiveMediaWarning.setOnClickListener(v -> {
|
||||||
|
if (getBindingAdapterPosition() != RecyclerView.NO_POSITION) {
|
||||||
|
listener.onContentHiddenChange(true, getBindingAdapterPosition());
|
||||||
|
}
|
||||||
|
v.setVisibility(View.GONE);
|
||||||
|
sensitiveMediaShow.setVisibility(View.VISIBLE);
|
||||||
|
});
|
||||||
|
|
||||||
// Hide any of the placeholder previews beyond the ones set.
|
return null;
|
||||||
for (int i = n; i < Status.MAX_MEDIA_ATTACHMENTS; i++) {
|
});
|
||||||
mediaPreviews[i].setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@DrawableRes
|
@DrawableRes
|
||||||
@ -751,10 +723,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||||||
} else {
|
} else {
|
||||||
setMediaLabel(attachments, sensitive, listener, status.isShowingContent());
|
setMediaLabel(attachments, sensitive, listener, status.isShowingContent());
|
||||||
// Hide all unused views.
|
// Hide all unused views.
|
||||||
mediaPreviews[0].setVisibility(View.GONE);
|
mediaPreview.setVisibility(View.GONE);
|
||||||
mediaPreviews[1].setVisibility(View.GONE);
|
|
||||||
mediaPreviews[2].setVisibility(View.GONE);
|
|
||||||
mediaPreviews[3].setVisibility(View.GONE);
|
|
||||||
hideSensitiveMediaWarning();
|
hideSensitiveMediaWarning();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.keylesspalace.tusky.adapter;
|
package com.keylesspalace.tusky.adapter;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -33,11 +32,6 @@ public class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
|||||||
infoDivider = view.findViewById(R.id.status_info_divider);
|
infoDivider = view.findViewById(R.id.status_info_divider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getMediaPreviewHeight(Context context) {
|
|
||||||
return context.getResources().getDimensionPixelSize(R.dimen.status_detail_media_preview_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setCreatedAt(Date createdAt, StatusDisplayOptions statusDisplayOptions) {
|
protected void setCreatedAt(Date createdAt, StatusDisplayOptions statusDisplayOptions) {
|
||||||
if (createdAt == null) {
|
if (createdAt == null) {
|
||||||
|
@ -53,11 +53,6 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||||||
contentCollapseButton = itemView.findViewById(R.id.button_toggle_content);
|
contentCollapseButton = itemView.findViewById(R.id.button_toggle_content);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getMediaPreviewHeight(Context context) {
|
|
||||||
return context.getResources().getDimensionPixelSize(R.dimen.status_media_preview_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setupWithStatus(@NonNull StatusViewData.Concrete status,
|
public void setupWithStatus(@NonNull StatusViewData.Concrete status,
|
||||||
@NonNull final StatusActionListener listener,
|
@NonNull final StatusActionListener listener,
|
||||||
|
@ -68,11 +68,6 @@ public class ConversationViewHolder extends StatusBaseViewHolder {
|
|||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getMediaPreviewHeight(Context context) {
|
|
||||||
return context.getResources().getDimensionPixelSize(R.dimen.status_media_preview_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupWithConversation(
|
void setupWithConversation(
|
||||||
@NonNull ConversationViewData conversation,
|
@NonNull ConversationViewData conversation,
|
||||||
@Nullable Object payloads
|
@Nullable Object payloads
|
||||||
@ -108,10 +103,7 @@ public class ConversationViewHolder extends StatusBaseViewHolder {
|
|||||||
} else {
|
} else {
|
||||||
setMediaLabel(attachments, sensitive, listener, statusViewData.isShowingContent());
|
setMediaLabel(attachments, sensitive, listener, statusViewData.isShowingContent());
|
||||||
// Hide all unused views.
|
// Hide all unused views.
|
||||||
mediaPreviews[0].setVisibility(View.GONE);
|
mediaPreview.setVisibility(View.GONE);
|
||||||
mediaPreviews[1].setVisibility(View.GONE);
|
|
||||||
mediaPreviews[2].setVisibility(View.GONE);
|
|
||||||
mediaPreviews[3].setVisibility(View.GONE);
|
|
||||||
hideSensitiveMediaWarning();
|
hideSensitiveMediaWarning();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,9 @@ data class Attachment(
|
|||||||
@Parcelize
|
@Parcelize
|
||||||
data class MetaData(
|
data class MetaData(
|
||||||
val focus: Focus?,
|
val focus: Focus?,
|
||||||
val duration: Float?
|
val duration: Float?,
|
||||||
|
val original: Size?,
|
||||||
|
val small: Size?,
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,4 +84,14 @@ data class Attachment(
|
|||||||
val x: Float,
|
val x: Float,
|
||||||
val y: Float
|
val y: Float
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of an image, used to specify the width/height.
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data class Size(
|
||||||
|
val width: Int,
|
||||||
|
val height: Int,
|
||||||
|
val aspect: Double
|
||||||
|
) : Parcelable
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
@file:JvmName("AttachmentHelper")
|
@file:JvmName("AttachmentHelper")
|
||||||
|
|
||||||
package com.keylesspalace.tusky.util
|
package com.keylesspalace.tusky.util
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
@ -24,3 +25,12 @@ private fun formatDuration(durationInSeconds: Double): String {
|
|||||||
val hours = durationInSeconds.toInt() / 3600
|
val hours = durationInSeconds.toInt() / 3600
|
||||||
return "%d:%02d:%02d".format(hours, minutes, seconds)
|
return "%d:%02d:%02d".format(hours, minutes, seconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun List<Attachment>.aspectRatios(): List<Double> {
|
||||||
|
return map { attachment ->
|
||||||
|
// clamp ratio between 2:1 & 1:2, defaulting to 16:9
|
||||||
|
val size = (attachment.meta?.small ?: attachment.meta?.original) ?: return@map 1.7778
|
||||||
|
val aspect = if (size.aspect > 0) size.aspect else size.width.toDouble() / size.height
|
||||||
|
aspect.coerceIn(0.5, 2.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -0,0 +1,210 @@
|
|||||||
|
package com.keylesspalace.tusky.view
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import com.keylesspalace.tusky.R
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lays out a set of [MediaPreviewImageView]s keeping their aspect ratios into account.
|
||||||
|
*/
|
||||||
|
class MediaPreviewLayout(context: Context, attrs: AttributeSet? = null) :
|
||||||
|
ViewGroup(context, attrs) {
|
||||||
|
|
||||||
|
private val spacing = context.resources.getDimensionPixelOffset(R.dimen.preview_image_spacing)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ordered list of aspect ratios used for layout. An image view for each aspect ratio passed
|
||||||
|
* will be attached. Supports up to 4, additional ones will be ignored.
|
||||||
|
*/
|
||||||
|
var aspectRatios: List<Double> = emptyList()
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
attachImageViews()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val imageViewCache = Array(4) { MediaPreviewImageView(context) }
|
||||||
|
|
||||||
|
private var measuredOrientation = LinearLayout.VERTICAL
|
||||||
|
|
||||||
|
private fun attachImageViews() {
|
||||||
|
removeAllViews()
|
||||||
|
for (i in 0 until aspectRatios.size.coerceAtMost(imageViewCache.size)) {
|
||||||
|
addView(imageViewCache[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||||
|
val width = MeasureSpec.getSize(widthMeasureSpec)
|
||||||
|
val halfWidth = width / 2 - spacing / 2
|
||||||
|
var totalHeight = 0
|
||||||
|
|
||||||
|
when (childCount) {
|
||||||
|
1 -> {
|
||||||
|
val aspect = aspectRatios[0]
|
||||||
|
totalHeight += getChildAt(0).measureToAspect(width, aspect)
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
val aspect1 = aspectRatios[0]
|
||||||
|
val aspect2 = aspectRatios[1]
|
||||||
|
|
||||||
|
if ((aspect1 + aspect2) / 2 > 1.2) {
|
||||||
|
// stack vertically
|
||||||
|
measuredOrientation = LinearLayout.VERTICAL
|
||||||
|
totalHeight += getChildAt(0).measureToAspect(width, aspect1.coerceAtLeast(1.8))
|
||||||
|
totalHeight += spacing
|
||||||
|
totalHeight += getChildAt(1).measureToAspect(width, aspect2.coerceAtLeast(1.8))
|
||||||
|
} else {
|
||||||
|
// stack horizontally
|
||||||
|
measuredOrientation = LinearLayout.HORIZONTAL
|
||||||
|
val height = rowHeight(halfWidth, aspect1, aspect2)
|
||||||
|
totalHeight += height
|
||||||
|
getChildAt(0).measureExactly(halfWidth, height)
|
||||||
|
getChildAt(1).measureExactly(halfWidth, height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
3 -> {
|
||||||
|
val aspect1 = aspectRatios[0]
|
||||||
|
val aspect2 = aspectRatios[1]
|
||||||
|
val aspect3 = aspectRatios[2]
|
||||||
|
if (aspect1 >= 1) {
|
||||||
|
// | 1 |
|
||||||
|
// -------------
|
||||||
|
// | 2 | 3 |
|
||||||
|
measuredOrientation = LinearLayout.VERTICAL
|
||||||
|
totalHeight += getChildAt(0).measureToAspect(width, aspect1.coerceAtLeast(1.8))
|
||||||
|
totalHeight += spacing
|
||||||
|
val bottomHeight = rowHeight(halfWidth, aspect2, aspect3)
|
||||||
|
totalHeight += bottomHeight
|
||||||
|
getChildAt(1).measureExactly(halfWidth, bottomHeight)
|
||||||
|
getChildAt(2).measureExactly(halfWidth, bottomHeight)
|
||||||
|
} else {
|
||||||
|
// | | 2 |
|
||||||
|
// | 1 |-----|
|
||||||
|
// | | 3 |
|
||||||
|
measuredOrientation = LinearLayout.HORIZONTAL
|
||||||
|
val colHeight = getChildAt(0).measureToAspect(halfWidth, aspect1)
|
||||||
|
totalHeight += colHeight
|
||||||
|
val halfHeight = colHeight / 2 - spacing / 2
|
||||||
|
getChildAt(1).measureExactly(halfWidth, halfHeight)
|
||||||
|
getChildAt(2).measureExactly(halfWidth, halfHeight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
4 -> {
|
||||||
|
val aspect1 = aspectRatios[0]
|
||||||
|
val aspect2 = aspectRatios[1]
|
||||||
|
val aspect3 = aspectRatios[2]
|
||||||
|
val aspect4 = aspectRatios[3]
|
||||||
|
val topHeight = rowHeight(halfWidth, aspect1, aspect2)
|
||||||
|
totalHeight += topHeight
|
||||||
|
getChildAt(0).measureExactly(halfWidth, topHeight)
|
||||||
|
getChildAt(1).measureExactly(halfWidth, topHeight)
|
||||||
|
totalHeight += spacing
|
||||||
|
val bottomHeight = rowHeight(halfWidth, aspect3, aspect4)
|
||||||
|
totalHeight += bottomHeight
|
||||||
|
getChildAt(2).measureExactly(halfWidth, bottomHeight)
|
||||||
|
getChildAt(3).measureExactly(halfWidth, bottomHeight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onMeasure(
|
||||||
|
widthMeasureSpec,
|
||||||
|
MeasureSpec.makeMeasureSpec(totalHeight, MeasureSpec.EXACTLY)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
|
||||||
|
val width = r - l
|
||||||
|
val height = b - t
|
||||||
|
val halfWidth = width / 2 - spacing / 2
|
||||||
|
when (childCount) {
|
||||||
|
1 -> {
|
||||||
|
getChildAt(0).layout(0, 0, width, height)
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
if (measuredOrientation == LinearLayout.VERTICAL) {
|
||||||
|
val y = imageViewCache[0].measuredHeight
|
||||||
|
getChildAt(0).layout(0, 0, width, y)
|
||||||
|
getChildAt(1).layout(
|
||||||
|
0,
|
||||||
|
y + spacing,
|
||||||
|
width,
|
||||||
|
y + spacing + getChildAt(1).measuredHeight
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
getChildAt(0).layout(0, 0, halfWidth, height)
|
||||||
|
getChildAt(1).layout(halfWidth + spacing, 0, width, height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
3 -> {
|
||||||
|
if (measuredOrientation == LinearLayout.VERTICAL) {
|
||||||
|
val y = getChildAt(0).measuredHeight
|
||||||
|
getChildAt(0).layout(0, 0, width, y)
|
||||||
|
getChildAt(1).layout(0, y + spacing, halfWidth, height)
|
||||||
|
getChildAt(2).layout(halfWidth + spacing, y + spacing, width, height)
|
||||||
|
} else {
|
||||||
|
val colHeight = getChildAt(0).measuredHeight
|
||||||
|
getChildAt(0).layout(0, 0, halfWidth, colHeight)
|
||||||
|
val halfHeight = colHeight / 2 - spacing / 2
|
||||||
|
getChildAt(1).layout(halfWidth + spacing, 0, width, halfHeight)
|
||||||
|
getChildAt(2).layout(
|
||||||
|
halfWidth + spacing,
|
||||||
|
halfHeight + spacing,
|
||||||
|
width,
|
||||||
|
colHeight
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
4 -> {
|
||||||
|
val topHeight = (getChildAt(0).measuredHeight + getChildAt(1).measuredHeight) / 2
|
||||||
|
getChildAt(0).layout(0, 0, halfWidth, topHeight)
|
||||||
|
getChildAt(1).layout(halfWidth + spacing, 0, width, topHeight)
|
||||||
|
val bottomHeight =
|
||||||
|
(imageViewCache[2].measuredHeight + imageViewCache[3].measuredHeight) / 2
|
||||||
|
getChildAt(2).layout(
|
||||||
|
0,
|
||||||
|
topHeight + spacing,
|
||||||
|
halfWidth,
|
||||||
|
topHeight + spacing + bottomHeight
|
||||||
|
)
|
||||||
|
getChildAt(3).layout(
|
||||||
|
halfWidth + spacing,
|
||||||
|
topHeight + spacing,
|
||||||
|
width,
|
||||||
|
topHeight + spacing + bottomHeight
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun forEachIndexed(action: (Int, MediaPreviewImageView) -> Unit) {
|
||||||
|
for (index in 0 until childCount) {
|
||||||
|
action(index, getChildAt(index) as MediaPreviewImageView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDraw(canvas: Canvas?) {
|
||||||
|
super.onDraw(canvas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rowHeight(halfWidth: Int, aspect1: Double, aspect2: Double): Int {
|
||||||
|
return ((halfWidth / aspect1 + halfWidth / aspect2) / 2).roundToInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun View.measureToAspect(width: Int, aspect: Double): Int {
|
||||||
|
val height = (width / aspect).roundToInt()
|
||||||
|
measureExactly(width, height)
|
||||||
|
return height
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun View.measureExactly(width: Int, height: Int) {
|
||||||
|
measure(
|
||||||
|
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
|
||||||
|
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)
|
||||||
|
)
|
||||||
|
}
|
6
app/src/main/res/drawable/play_indicator_overlay.xml
Normal file
6
app/src/main/res/drawable/play_indicator_overlay.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:drawable="@drawable/ic_play_indicator"
|
||||||
|
android:gravity="center" />
|
||||||
|
</layer-list>
|
@ -1,198 +1,113 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.MediaPreviewImageView
|
<com.keylesspalace.tusky.view.MediaPreviewLayout
|
||||||
android:id="@+id/status_media_preview_0"
|
android:id="@+id/status_media_preview"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="@dimen/status_media_preview_height"
|
android:layout_height="wrap_content"
|
||||||
android:scaleType="centerCrop"
|
app:layout_constraintEnd_toStartOf="@+id/status_media_preview_1"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/status_media_preview_1"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:ignore="ContentDescription" />
|
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.MediaPreviewImageView
|
<ImageView
|
||||||
android:id="@+id/status_media_preview_1"
|
android:id="@+id/status_sensitive_media_button"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="@dimen/status_media_preview_height"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="4dp"
|
android:alpha="0.7"
|
||||||
android:scaleType="centerCrop"
|
android:contentDescription="@null"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:padding="@dimen/status_sensitive_media_button_padding"
|
||||||
app:layout_constraintStart_toEndOf="@+id/status_media_preview_0"
|
android:visibility="gone"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintLeft_toLeftOf="@+id/status_media_preview_container"
|
||||||
tools:ignore="ContentDescription" />
|
app:layout_constraintTop_toTopOf="@+id/status_media_preview_container"
|
||||||
|
app:srcCompat="@drawable/ic_eye_24dp"
|
||||||
|
app:tint="@color/white" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.MediaPreviewImageView
|
<TextView
|
||||||
android:id="@+id/status_media_preview_2"
|
android:id="@+id/status_sensitive_media_warning"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="@dimen/status_media_preview_height"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:background="@drawable/media_warning_bg"
|
||||||
android:scaleType="centerCrop"
|
android:gravity="center"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/status_media_preview_3"
|
android:lineSpacingMultiplier="1.2"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
android:orientation="vertical"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/status_media_preview_0"
|
android:paddingLeft="12dp"
|
||||||
tools:ignore="ContentDescription" />
|
android:paddingTop="8dp"
|
||||||
|
android:paddingRight="12dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:textSize="?attr/status_text_medium"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.MediaPreviewImageView
|
<TextView
|
||||||
android:id="@+id/status_media_preview_3"
|
android:id="@+id/status_media_label_0"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="@dimen/status_media_preview_height"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="4dp"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:layout_marginTop="4dp"
|
android:drawablePadding="4dp"
|
||||||
android:background="@drawable/media_preview_outline"
|
android:ellipsize="end"
|
||||||
android:scaleType="centerCrop"
|
android:gravity="center_vertical"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:importantForAccessibility="no"
|
||||||
app:layout_constraintStart_toEndOf="@+id/status_media_preview_2"
|
android:maxLines="10"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/status_media_preview_1"
|
android:textSize="?attr/status_text_medium"
|
||||||
tools:ignore="ContentDescription" />
|
android:visibility="gone"
|
||||||
|
app:drawableTint="?android:attr/textColorTertiary"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<ImageView
|
<TextView
|
||||||
android:id="@+id/status_media_overlay_0"
|
android:id="@+id/status_media_label_1"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
android:scaleType="center"
|
android:background="?attr/selectableItemBackground"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/status_media_preview_0"
|
android:drawablePadding="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="@+id/status_media_preview_0"
|
android:ellipsize="end"
|
||||||
app:layout_constraintStart_toStartOf="@+id/status_media_preview_0"
|
android:gravity="center_vertical"
|
||||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_0"
|
android:importantForAccessibility="no"
|
||||||
app:srcCompat="@drawable/ic_play_indicator"
|
android:maxLines="10"
|
||||||
tools:ignore="ContentDescription" />
|
android:textSize="?attr/status_text_medium"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:drawableTint="?android:attr/textColorTertiary"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/status_media_label_0" />
|
||||||
|
|
||||||
<ImageView
|
<TextView
|
||||||
android:id="@+id/status_media_overlay_1"
|
android:id="@+id/status_media_label_2"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
android:scaleType="center"
|
android:background="?attr/selectableItemBackground"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/status_media_preview_1"
|
android:drawablePadding="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="@+id/status_media_preview_1"
|
android:ellipsize="end"
|
||||||
app:layout_constraintStart_toStartOf="@+id/status_media_preview_1"
|
android:gravity="center_vertical"
|
||||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_1"
|
android:importantForAccessibility="no"
|
||||||
app:srcCompat="@drawable/ic_play_indicator"
|
android:maxLines="10"
|
||||||
tools:ignore="ContentDescription" />
|
android:textSize="?attr/status_text_medium"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:drawableTint="?android:attr/textColorTertiary"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/status_media_label_1" />
|
||||||
|
|
||||||
<ImageView
|
<TextView
|
||||||
android:id="@+id/status_media_overlay_2"
|
android:id="@+id/status_media_label_3"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
android:scaleType="center"
|
android:background="?attr/selectableItemBackground"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/status_media_preview_2"
|
android:drawablePadding="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="@+id/status_media_preview_2"
|
android:ellipsize="end"
|
||||||
app:layout_constraintStart_toStartOf="@+id/status_media_preview_2"
|
android:gravity="center_vertical"
|
||||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_2"
|
android:importantForAccessibility="no"
|
||||||
app:srcCompat="@drawable/ic_play_indicator"
|
android:maxLines="10"
|
||||||
tools:ignore="ContentDescription" />
|
android:textSize="?attr/status_text_medium"
|
||||||
|
android:visibility="gone"
|
||||||
<ImageView
|
app:drawableTint="?android:attr/textColorTertiary"
|
||||||
android:id="@+id/status_media_overlay_3"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
android:layout_width="0dp"
|
app:layout_constraintTop_toBottomOf="@id/status_media_label_2" />
|
||||||
android:layout_height="0dp"
|
|
||||||
android:scaleType="center"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/status_media_preview_3"
|
|
||||||
app:layout_constraintEnd_toEndOf="@+id/status_media_preview_3"
|
|
||||||
app:layout_constraintStart_toStartOf="@+id/status_media_preview_3"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_3"
|
|
||||||
app:srcCompat="@drawable/ic_play_indicator"
|
|
||||||
tools:ignore="ContentDescription" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/status_sensitive_media_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:alpha="0.7"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:padding="@dimen/status_sensitive_media_button_padding"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintLeft_toLeftOf="@+id/status_media_preview_container"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_container"
|
|
||||||
app:srcCompat="@drawable/ic_eye_24dp"
|
|
||||||
app:tint="@color/white" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/status_sensitive_media_warning"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/media_warning_bg"
|
|
||||||
android:gravity="center"
|
|
||||||
android:lineSpacingMultiplier="1.2"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingLeft="12dp"
|
|
||||||
android:paddingTop="8dp"
|
|
||||||
android:paddingRight="12dp"
|
|
||||||
android:paddingBottom="8dp"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
android:textSize="?attr/status_text_medium"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/status_media_label_0"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:drawablePadding="4dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:importantForAccessibility="no"
|
|
||||||
android:textSize="?attr/status_text_medium"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:maxLines="10"
|
|
||||||
android:ellipsize="end"
|
|
||||||
app:drawableTint="?android:attr/textColorTertiary"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/status_media_label_1"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:drawablePadding="4dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:importantForAccessibility="no"
|
|
||||||
android:textSize="?attr/status_text_medium"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:maxLines="10"
|
|
||||||
android:ellipsize="end"
|
|
||||||
app:drawableTint="?android:attr/textColorTertiary"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/status_media_label_0" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/status_media_label_2"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:drawablePadding="4dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:importantForAccessibility="no"
|
|
||||||
android:textSize="?attr/status_text_medium"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:maxLines="10"
|
|
||||||
android:ellipsize="end"
|
|
||||||
app:drawableTint="?android:attr/textColorTertiary"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/status_media_label_1" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/status_media_label_3"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:drawablePadding="4dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:importantForAccessibility="no"
|
|
||||||
android:textSize="?attr/status_text_medium"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:maxLines="10"
|
|
||||||
android:ellipsize="end"
|
|
||||||
app:drawableTint="?android:attr/textColorTertiary"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/status_media_label_2" />
|
|
||||||
|
|
||||||
</merge>
|
</merge>
|
||||||
|
@ -58,4 +58,5 @@
|
|||||||
|
|
||||||
<dimen name="profile_media_audio_icon_padding">16dp</dimen>
|
<dimen name="profile_media_audio_icon_padding">16dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="preview_image_spacing">4dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user