diff --git a/app/src/main/java/org/thoughtcrime/securesms/MediaGalleryAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/MediaGalleryAdapter.java index 0fd813cf4..62766d1cd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MediaGalleryAdapter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/MediaGalleryAdapter.java @@ -114,7 +114,7 @@ class MediaGalleryAdapter extends StickyHeaderGridAdapter { Slide slide = MediaUtil.getSlideForAttachment(context, mediaRecord.getAttachment()); if (slide != null) { - thumbnailView.setImageResource(glideRequests, slide, false, null); + thumbnailView.setImageResource(glideRequests, slide, false); } thumbnailView.setOnClickListener(view -> itemClickListener.onMediaClicked(mediaRecord)); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt index d76e6f2b3..f646ace97 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt @@ -104,7 +104,7 @@ class AlbumThumbnailView : RelativeLayout { // iterate binding slides.take(MAX_ALBUM_DISPLAY_SIZE).forEachIndexed { position, slide -> val thumbnailView = getThumbnailView(position) - thumbnailView.setImageResource(glideRequests, slide, isPreview = false, mms = message) + thumbnailView.setImageResource(glideRequests, slide, isPreview = false) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/LinkPreviewDraftView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/LinkPreviewDraftView.kt index 66164f100..33af3588d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/LinkPreviewDraftView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/LinkPreviewDraftView.kt @@ -34,7 +34,7 @@ class LinkPreviewDraftView : LinearLayout { binding.thumbnailImageView.root.radius = toPx(4, resources) if (linkPreview.getThumbnail().isPresent) { // This internally fetches the thumbnail - binding.thumbnailImageView.root.setImageResource(glide, ImageSlide(context, linkPreview.getThumbnail().get()), false, null) + binding.thumbnailImageView.root.setImageResource(glide, ImageSlide(context, linkPreview.getThumbnail().get()), false) } binding.linkPreviewDraftTitleTextView.text = linkPreview.title } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt index 967722389..4e6066edb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt @@ -41,7 +41,7 @@ class LinkPreviewView : LinearLayout { // Thumbnail if (linkPreview.getThumbnail().isPresent) { // This internally fetches the thumbnail - binding.thumbnailImageView.root.setImageResource(glide, ImageSlide(context, linkPreview.getThumbnail().get()), isPreview = false, message) + binding.thumbnailImageView.root.setImageResource(glide, ImageSlide(context, linkPreview.getThumbnail().get()), isPreview = false) binding.thumbnailImageView.root.loadIndicator.isVisible = false } // Title diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt index 4e9140043..ddd8fb94d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt @@ -109,7 +109,7 @@ class QuoteView @JvmOverloads constructor(context: Context, attrs: AttributeSet? val slide = attachments.thumbnailSlide!! // This internally fetches the thumbnail binding.quoteViewAttachmentThumbnailImageView.root.radius = toPx(4, resources) - binding.quoteViewAttachmentThumbnailImageView.root.setImageResource(glide, slide, false, null) + binding.quoteViewAttachmentThumbnailImageView.root.setImageResource(glide, slide, false) binding.quoteViewAttachmentThumbnailImageView.root.isVisible = true binding.quoteViewBodyTextView.text = if (MediaUtil.isVideo(slide.asAttachment())) resources.getString(R.string.Slide_video) else resources.getString(R.string.Slide_image) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.kt index 4a9986d6e..ed9b1a30f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.kt @@ -21,18 +21,17 @@ import org.session.libsignal.utilities.ListenableFuture import org.session.libsignal.utilities.SettableFuture import org.thoughtcrime.securesms.components.GlideBitmapListeningTarget import org.thoughtcrime.securesms.components.GlideDrawableListeningTarget -import org.thoughtcrime.securesms.database.model.MmsMessageRecord import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri import org.thoughtcrime.securesms.mms.GlideRequest import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.mms.Slide -import kotlin.Boolean -import kotlin.Int -import kotlin.getValue -import kotlin.lazy -import kotlin.let -open class ThumbnailView: FrameLayout { +open class ThumbnailView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + companion object { private const val WIDTH = 0 private const val HEIGHT = 1 @@ -41,9 +40,6 @@ open class ThumbnailView: FrameLayout { private val binding: ThumbnailViewBinding by lazy { ThumbnailViewBinding.bind(this) } // region Lifecycle - constructor(context: Context) : super(context) { initialize(null) } - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize(attrs) } - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize(attrs) } val loadIndicator: View by lazy { binding.thumbnailLoadIndicator } @@ -52,19 +48,20 @@ open class ThumbnailView: FrameLayout { private var slide: Slide? = null var radius: Int = 0 - private fun initialize(attrs: AttributeSet?) { - if (attrs != null) { - val typedArray = context.theme.obtainStyledAttributes(attrs, R.styleable.ThumbnailView, 0, 0) + init { + attrs?.let { context.theme.obtainStyledAttributes(it, R.styleable.ThumbnailView, 0, 0) } + ?.apply { + dimensDelegate.setBounds( + getDimensionPixelSize(R.styleable.ThumbnailView_minWidth, 0), + getDimensionPixelSize(R.styleable.ThumbnailView_minHeight, 0), + getDimensionPixelSize(R.styleable.ThumbnailView_maxWidth, 0), + getDimensionPixelSize(R.styleable.ThumbnailView_maxHeight, 0) + ) - dimensDelegate.setBounds(typedArray.getDimensionPixelSize(R.styleable.ThumbnailView_minWidth, 0), - typedArray.getDimensionPixelSize(R.styleable.ThumbnailView_minHeight, 0), - typedArray.getDimensionPixelSize(R.styleable.ThumbnailView_maxWidth, 0), - typedArray.getDimensionPixelSize(R.styleable.ThumbnailView_maxHeight, 0)) + radius = getDimensionPixelSize(R.styleable.ThumbnailView_thumbnail_radius, 0) - radius = typedArray.getDimensionPixelSize(R.styleable.ThumbnailView_thumbnail_radius, 0) - - typedArray.recycle() - } + recycle() + } } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { @@ -87,111 +84,104 @@ open class ThumbnailView: FrameLayout { // endregion // region Interaction - fun setImageResource(glide: GlideRequests, slide: Slide, isPreview: Boolean, mms: MmsMessageRecord?): ListenableFuture { - return setImageResource(glide, slide, isPreview, 0, 0, mms) - } - - fun setImageResource(glide: GlideRequests, slide: Slide, - isPreview: Boolean, naturalWidth: Int, - naturalHeight: Int, mms: MmsMessageRecord?): ListenableFuture { - - val currentSlide = this.slide + fun setImageResource( + glide: GlideRequests, + slide: Slide, + isPreview: Boolean + ): ListenableFuture = setImageResource(glide, slide, isPreview, 0, 0) + fun setImageResource( + glide: GlideRequests, slide: Slide, + isPreview: Boolean, naturalWidth: Int, + naturalHeight: Int + ): ListenableFuture { binding.playOverlay.isVisible = (slide.thumbnailUri != null && slide.hasPlayOverlay() && - (slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_DONE || isPreview)) + (slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_DONE || isPreview)) - if (equals(currentSlide, slide)) { + if (equals(this.slide, slide)) { // don't re-load slide return SettableFuture(false) } - - if (currentSlide != null && currentSlide.fastPreflightId != null && currentSlide.fastPreflightId == slide.fastPreflightId) { - // not reloading slide for fast preflight - this.slide = slide - } - this.slide = slide binding.thumbnailLoadIndicator.isVisible = slide.isInProgress - binding.thumbnailDownloadIcon.isVisible = slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_FAILED + binding.thumbnailDownloadIcon.isVisible = + slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_FAILED dimensDelegate.setDimens(naturalWidth, naturalHeight) invalidate() - val result = SettableFuture() - - when { - slide.thumbnailUri != null -> { - buildThumbnailGlideRequest(glide, slide).into(GlideDrawableListeningTarget(binding.thumbnailImage, binding.thumbnailLoadIndicator, result)) - } - slide.hasPlaceholder() -> { - buildPlaceholderGlideRequest(glide, slide).into(GlideBitmapListeningTarget(binding.thumbnailImage, null, result)) - } - else -> { - glide.clear(binding.thumbnailImage) - result.set(false) + return SettableFuture().also { + when { + slide.thumbnailUri != null -> { + buildThumbnailGlideRequest(glide, slide).into( + GlideDrawableListeningTarget(binding.thumbnailImage, binding.thumbnailLoadIndicator, it) + ) + } + slide.hasPlaceholder() -> { + buildPlaceholderGlideRequest(glide, slide).into( + GlideBitmapListeningTarget(binding.thumbnailImage, null, it) + ) + } + else -> { + glide.clear(binding.thumbnailImage) + it.set(false) + } } } - return result } - fun buildThumbnailGlideRequest(glide: GlideRequests, slide: Slide): GlideRequest { + private fun buildThumbnailGlideRequest( + glide: GlideRequests, + slide: Slide + ): GlideRequest = glide.load(DecryptableUri(slide.thumbnailUri!!)) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .overrideDimensions() + .transition(DrawableTransitionOptions.withCrossFade()) + .crop(radius) + .missingThumbnailPicture(slide.isInProgress) - val dimens = dimensDelegate.resourceSize() - - val request = glide.load(DecryptableUri(slide.thumbnailUri!!)) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .let { request -> - if (dimens[WIDTH] == 0 || dimens[HEIGHT] == 0) { - request.override(getDefaultWidth(), getDefaultHeight()) - } else { - request.override(dimens[WIDTH], dimens[HEIGHT]) - } - } - .transition(DrawableTransitionOptions.withCrossFade()) - .centerCrop() - - return if (slide.isInProgress) request else request.apply(RequestOptions.errorOf(R.drawable.ic_missing_thumbnail_picture)) - } - - fun buildPlaceholderGlideRequest(glide: GlideRequests, slide: Slide): GlideRequest { - - val dimens = dimensDelegate.resourceSize() - - return glide.asBitmap() - .load(slide.getPlaceholderRes(context.theme)) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .let { request -> - if (dimens[WIDTH] == 0 || dimens[HEIGHT] == 0) { - request.override(getDefaultWidth(), getDefaultHeight()) - } else { - request.override(dimens[WIDTH], dimens[HEIGHT]) - } - } - .fitCenter() - } + private fun buildPlaceholderGlideRequest( + glide: GlideRequests, + slide: Slide + ): GlideRequest = glide.asBitmap() + .load(slide.getPlaceholderRes(context.theme)) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .overrideDimensions() + .fitCenter() open fun clear(glideRequests: GlideRequests) { glideRequests.clear(binding.thumbnailImage) slide = null } - fun setImageResource(glideRequests: GlideRequests, uri: Uri): ListenableFuture { - val future = SettableFuture() + fun setImageResource( + glideRequests: GlideRequests, + uri: Uri + ): ListenableFuture = glideRequests.load(DecryptableUri(uri)) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .transition(DrawableTransitionOptions.withCrossFade()) + .crop(radius) + .intoDrawableTargetAsFuture() - var request: GlideRequest = glideRequests.load(DecryptableUri(uri)) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .transition(DrawableTransitionOptions.withCrossFade()) - - request = if (radius > 0) { - request.transforms(CenterCrop(), RoundedCorners(radius)) - } else { - request.transforms(CenterCrop()) + private fun GlideRequest.intoDrawableTargetAsFuture() = + SettableFuture().also { + binding.run { + GlideDrawableListeningTarget(thumbnailImage, thumbnailLoadIndicator, it) + }.let { into(it) } } - request.into(GlideDrawableListeningTarget(binding.thumbnailImage, binding.thumbnailLoadIndicator, future)) + private fun GlideRequest.overrideDimensions() = + dimensDelegate.resourceSize().takeIf { 0 !in it } + ?.let { override(it[WIDTH], it[HEIGHT]) } + ?: override(getDefaultWidth(), getDefaultHeight()) - return future - } -} \ No newline at end of file + private fun GlideRequest.crop(radius: Int) = + if (radius > 0) transforms(CenterCrop(), RoundedCorners(radius)) + else transforms(CenterCrop()) +} + +private fun GlideRequest.missingThumbnailPicture( + inProgress: Boolean +) = takeIf { inProgress } ?: apply(RequestOptions.errorOf(R.drawable.ic_missing_thumbnail_picture))