mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-23 20:48:43 +00:00
Polish thumbnail animation.
This commit is contained in:
committed by
Greyson Parrelli
parent
417db2341b
commit
c027203e8c
@@ -1,9 +1,8 @@
|
|||||||
package org.thoughtcrime.securesms.components;
|
package org.thoughtcrime.securesms.components;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -29,13 +28,13 @@ public class AlbumThumbnailView extends FrameLayout {
|
|||||||
|
|
||||||
private int currentSizeClass;
|
private int currentSizeClass;
|
||||||
|
|
||||||
|
private final int[] corners = new int[4];
|
||||||
|
|
||||||
private ViewGroup albumCellContainer;
|
private ViewGroup albumCellContainer;
|
||||||
private Stub<TransferControlView> transferControls;
|
private Stub<TransferControlView> transferControls;
|
||||||
private Drawable imageDrawable;
|
|
||||||
|
|
||||||
private final SlideClickListener defaultThumbnailClickListener = (v, slide) -> {
|
private final SlideClickListener defaultThumbnailClickListener = (v, slide) -> {
|
||||||
if (thumbnailClickListener != null) {
|
if (thumbnailClickListener != null) {
|
||||||
imageDrawable = ((ThumbnailView) v).getImageDrawable();
|
|
||||||
thumbnailClickListener.onClick(v, slide);
|
thumbnailClickListener.onClick(v, slide);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -86,10 +85,7 @@ public class AlbumThumbnailView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showSlides(glideRequests, slides);
|
showSlides(glideRequests, slides);
|
||||||
}
|
applyCorners();
|
||||||
|
|
||||||
public @Nullable Drawable getDrawable() {
|
|
||||||
return imageDrawable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCellBackgroundColor(@ColorInt int color) {
|
public void setCellBackgroundColor(@ColorInt int color) {
|
||||||
@@ -110,6 +106,15 @@ public class AlbumThumbnailView extends FrameLayout {
|
|||||||
downloadClickListener = listener;
|
downloadClickListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRadii(int topLeft, int topRight, int bottomRight, int bottomLeft) {
|
||||||
|
corners[0] = topLeft;
|
||||||
|
corners[1] = topRight;
|
||||||
|
corners[2] = bottomRight;
|
||||||
|
corners[3] = bottomLeft;
|
||||||
|
|
||||||
|
applyCorners();
|
||||||
|
}
|
||||||
|
|
||||||
private void inflateLayout(int sizeClass) {
|
private void inflateLayout(int sizeClass) {
|
||||||
albumCellContainer.removeAllViews();
|
albumCellContainer.removeAllViews();
|
||||||
|
|
||||||
@@ -132,6 +137,73 @@ public class AlbumThumbnailView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applyCorners() {
|
||||||
|
if (currentSizeClass < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (currentSizeClass) {
|
||||||
|
case 2:
|
||||||
|
applyCornersForSizeClass2();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
applyCornersForSizeClass3();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
applyCornersForSizeClass4();
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
applyCornersForSizeClass5();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
applyCornersForManySizeClass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ThumbnailView[] getCells() {
|
||||||
|
ThumbnailView one = findViewById(R.id.album_cell_1);
|
||||||
|
ThumbnailView two = findViewById(R.id.album_cell_2);
|
||||||
|
ThumbnailView three = findViewById(R.id.album_cell_3);
|
||||||
|
ThumbnailView four = findViewById(R.id.album_cell_4);
|
||||||
|
ThumbnailView five = findViewById(R.id.album_cell_5);
|
||||||
|
|
||||||
|
return new ThumbnailView[]{one, two, three, four, five};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyCornersForSizeClass2() {
|
||||||
|
ThumbnailView[] cells = getCells();
|
||||||
|
cells[0].setRadii(corners[0], 0, 0, corners[3]);
|
||||||
|
cells[1].setRadii(0, corners[1], corners[2], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyCornersForSizeClass3() {
|
||||||
|
ThumbnailView[] cells = getCells();
|
||||||
|
cells[0].setRadii(corners[0], 0, 0, corners[3]);
|
||||||
|
cells[1].setRadii(0, corners[1], 0, 0);
|
||||||
|
cells[2].setRadii(0, 0, corners[2], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyCornersForSizeClass4() {
|
||||||
|
ThumbnailView[] cells = getCells();
|
||||||
|
cells[0].setRadii(corners[0], 0, 0, 0);
|
||||||
|
cells[1].setRadii(0, corners[1], 0, 0);
|
||||||
|
cells[2].setRadii(0, 0, 0, corners[3]);
|
||||||
|
cells[3].setRadii(0, 0, corners[2], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyCornersForSizeClass5() {
|
||||||
|
ThumbnailView[] cells = getCells();
|
||||||
|
cells[0].setRadii(corners[0], 0, 0, 0);
|
||||||
|
cells[1].setRadii(0, corners[1], 0, 0);
|
||||||
|
cells[2].setRadii(0, 0, 0, corners[3]);
|
||||||
|
cells[3].setRadii(0, 0, 0, 0);
|
||||||
|
cells[4].setRadii(0, 0, corners[2], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyCornersForManySizeClass() {
|
||||||
|
applyCornersForSizeClass5();
|
||||||
|
}
|
||||||
|
|
||||||
private void showSlides(@NonNull GlideRequests glideRequests, @NonNull List<Slide> slides) {
|
private void showSlides(@NonNull GlideRequests glideRequests, @NonNull List<Slide> slides) {
|
||||||
setSlide(glideRequests, slides.get(0), R.id.album_cell_1);
|
setSlide(glideRequests, slides.get(0), R.id.album_cell_1);
|
||||||
setSlide(glideRequests, slides.get(1), R.id.album_cell_2);
|
setSlide(glideRequests, slides.get(1), R.id.album_cell_2);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.components
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
@@ -131,14 +130,6 @@ class ConversationItemThumbnail @JvmOverloads constructor(
|
|||||||
state.applyState(thumbnail, album)
|
state.applyState(thumbnail, album)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDrawable(): Drawable? {
|
|
||||||
return if (thumbnail.resolved()) {
|
|
||||||
thumbnail.get().imageDrawable
|
|
||||||
} else {
|
|
||||||
album.get().drawable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hideThumbnailView() {
|
fun hideThumbnailView() {
|
||||||
state = state.copy(thumbnailViewState = state.thumbnailViewState.copy(alpha = 0f))
|
state = state.copy(thumbnailViewState = state.thumbnailViewState.copy(alpha = 0f))
|
||||||
state.thumbnailViewState.applyState(thumbnail)
|
state.thumbnailViewState.applyState(thumbnail)
|
||||||
@@ -159,6 +150,22 @@ class ConversationItemThumbnail @JvmOverloads constructor(
|
|||||||
|
|
||||||
fun setCorners(topLeft: Int, topRight: Int, bottomRight: Int, bottomLeft: Int) {
|
fun setCorners(topLeft: Int, topRight: Int, bottomRight: Int, bottomLeft: Int) {
|
||||||
cornerMask.setRadii(topLeft, topRight, bottomRight, bottomLeft)
|
cornerMask.setRadii(topLeft, topRight, bottomRight, bottomLeft)
|
||||||
|
state = state.copy(
|
||||||
|
thumbnailViewState = state.thumbnailViewState.copy(
|
||||||
|
cornerTopLeft = topLeft,
|
||||||
|
cornerTopRight = topRight,
|
||||||
|
cornerBottomRight = bottomRight,
|
||||||
|
cornerBottomLeft = bottomLeft
|
||||||
|
),
|
||||||
|
albumViewState = state.albumViewState.copy(
|
||||||
|
cornerTopLeft = topLeft,
|
||||||
|
cornerTopRight = topRight,
|
||||||
|
cornerBottomRight = bottomRight,
|
||||||
|
cornerBottomLeft = bottomLeft
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
state.applyState(thumbnail, album)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setMinimumThumbnailWidth(@Px width: Int) {
|
fun setMinimumThumbnailWidth(@Px width: Int) {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import org.thoughtcrime.securesms.mms.SlidesClickedListener
|
|||||||
import org.thoughtcrime.securesms.util.views.Stub
|
import org.thoughtcrime.securesms.util.views.Stub
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parcelizable state object for [ConversationItemThumbnail]
|
* Parcelable state object for [ConversationItemThumbnail]
|
||||||
* This allows us to manage inputs for [ThumbnailView] and [AlbumThumbnailView] without
|
* This allows us to manage inputs for [ThumbnailView] and [AlbumThumbnailView] without
|
||||||
* actually having them inflated. When the views are finally inflated, we 'apply'
|
* actually having them inflated. When the views are finally inflated, we 'apply'
|
||||||
*/
|
*/
|
||||||
@@ -38,7 +38,11 @@ data class ConversationItemThumbnailState(
|
|||||||
private val minWidth: Int = -1,
|
private val minWidth: Int = -1,
|
||||||
private val maxWidth: Int = -1,
|
private val maxWidth: Int = -1,
|
||||||
private val minHeight: Int = -1,
|
private val minHeight: Int = -1,
|
||||||
private val maxHeight: Int = -1
|
private val maxHeight: Int = -1,
|
||||||
|
private val cornerTopLeft: Int = 0,
|
||||||
|
private val cornerTopRight: Int = 0,
|
||||||
|
private val cornerBottomRight: Int = 0,
|
||||||
|
private val cornerBottomLeft: Int = 0
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
fun applyState(thumbnailView: Stub<ThumbnailView>) {
|
fun applyState(thumbnailView: Stub<ThumbnailView>) {
|
||||||
@@ -50,6 +54,7 @@ data class ConversationItemThumbnailState(
|
|||||||
thumbnailView.get().alpha = alpha
|
thumbnailView.get().alpha = alpha
|
||||||
thumbnailView.get().isFocusable = focusable
|
thumbnailView.get().isFocusable = focusable
|
||||||
thumbnailView.get().isClickable = clickable
|
thumbnailView.get().isClickable = clickable
|
||||||
|
thumbnailView.get().setRadii(cornerTopLeft, cornerTopRight, cornerBottomRight, cornerBottomLeft)
|
||||||
thumbnailView.get().setThumbnailClickListener(clickListener)
|
thumbnailView.get().setThumbnailClickListener(clickListener)
|
||||||
thumbnailView.get().setDownloadClickListener(downloadClickListener)
|
thumbnailView.get().setDownloadClickListener(downloadClickListener)
|
||||||
thumbnailView.get().setOnLongClickListener(longClickListener)
|
thumbnailView.get().setOnLongClickListener(longClickListener)
|
||||||
@@ -70,7 +75,11 @@ data class ConversationItemThumbnailState(
|
|||||||
@IgnoredOnParcel
|
@IgnoredOnParcel
|
||||||
private val longClickListener: OnLongClickListener? = null,
|
private val longClickListener: OnLongClickListener? = null,
|
||||||
private val visibility: Int = View.GONE,
|
private val visibility: Int = View.GONE,
|
||||||
private val cellBackgroundColor: Int = Color.TRANSPARENT
|
private val cellBackgroundColor: Int = Color.TRANSPARENT,
|
||||||
|
private val cornerTopLeft: Int = 0,
|
||||||
|
private val cornerTopRight: Int = 0,
|
||||||
|
private val cornerBottomRight: Int = 0,
|
||||||
|
private val cornerBottomLeft: Int = 0
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
fun applyState(albumView: Stub<AlbumThumbnailView>) {
|
fun applyState(albumView: Stub<AlbumThumbnailView>) {
|
||||||
@@ -81,6 +90,7 @@ data class ConversationItemThumbnailState(
|
|||||||
|
|
||||||
albumView.get().isFocusable = focusable
|
albumView.get().isFocusable = focusable
|
||||||
albumView.get().isClickable = clickable
|
albumView.get().isClickable = clickable
|
||||||
|
albumView.get().setRadii(cornerTopLeft, cornerTopRight, cornerBottomRight, cornerBottomLeft)
|
||||||
albumView.get().setThumbnailClickListener(clickListener)
|
albumView.get().setThumbnailClickListener(clickListener)
|
||||||
albumView.get().setDownloadClickListener(downloadClickListener)
|
albumView.get().setDownloadClickListener(downloadClickListener)
|
||||||
albumView.get().setOnLongClickListener(longClickListener)
|
albumView.get().setOnLongClickListener(longClickListener)
|
||||||
|
|||||||
@@ -529,6 +529,11 @@ public class ThumbnailView extends FrameLayout {
|
|||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRadii(int topLeft, int topRight, int bottomRight, int bottomLeft) {
|
||||||
|
cornerMask.setRadii(topLeft, topRight, bottomRight, bottomLeft);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
private GlideRequest<Drawable> buildThumbnailGlideRequest(@NonNull GlideRequests glideRequests, @NonNull Slide slide) {
|
private GlideRequest<Drawable> buildThumbnailGlideRequest(@NonNull GlideRequests glideRequests, @NonNull Slide slide) {
|
||||||
GlideRequest<Drawable> request = applySizing(glideRequests.load(new DecryptableUri(Objects.requireNonNull(slide.getUri())))
|
GlideRequest<Drawable> request = applySizing(glideRequests.load(new DecryptableUri(Objects.requireNonNull(slide.getUri())))
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ import org.thoughtcrime.securesms.components.Outliner;
|
|||||||
import org.thoughtcrime.securesms.components.PlaybackSpeedToggleTextView;
|
import org.thoughtcrime.securesms.components.PlaybackSpeedToggleTextView;
|
||||||
import org.thoughtcrime.securesms.components.QuoteView;
|
import org.thoughtcrime.securesms.components.QuoteView;
|
||||||
import org.thoughtcrime.securesms.components.SharedContactView;
|
import org.thoughtcrime.securesms.components.SharedContactView;
|
||||||
|
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||||
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
|
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
|
||||||
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
|
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
|
||||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||||
@@ -2393,8 +2394,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
|||||||
mediaThumbnailStub.require().getCorners().getBottomRight(),
|
mediaThumbnailStub.require().getCorners().getBottomRight(),
|
||||||
mediaThumbnailStub.require().getCorners().getBottomLeft()
|
mediaThumbnailStub.require().getCorners().getBottomLeft()
|
||||||
));
|
));
|
||||||
MediaPreviewCache.INSTANCE.setDrawable(mediaThumbnailStub.require().getDrawable());
|
MediaPreviewCache.INSTANCE.setDrawable(((ThumbnailView) v).getImageDrawable());
|
||||||
eventListener.goToMediaPreview(ConversationItem.this, mediaThumbnailStub.require(), args);
|
eventListener.goToMediaPreview(ConversationItem.this, v, args);
|
||||||
} else if (slide.getUri() != null) {
|
} else if (slide.getUri() != null) {
|
||||||
Log.i(TAG, "Clicked: " + slide.getUri() + " , " + slide.getContentType());
|
Log.i(TAG, "Clicked: " + slide.getUri() + " , " + slide.getContentType());
|
||||||
Uri publicUri = PartAuthority.getAttachmentPublicUri(slide.getUri());
|
Uri publicUri = PartAuthority.getAttachmentPublicUri(slide.getUri());
|
||||||
|
|||||||
Reference in New Issue
Block a user