From bc1c8032c1233dad40bfa5d242cf8bec1e102d82 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Fri, 1 Sep 2023 11:30:47 -0300 Subject: [PATCH] Add support for shade and arbitrary overlay drawables to CIV2 Media items. --- .../conversation/ConversationItem.java | 4 +- .../V2ConversationItemMediaBindingBridge.kt | 3 +- .../V2ConversationItemMediaViewHolder.kt | 155 +---------- .../V2ConversationItemTextOnlyViewHolder.kt | 2 +- .../v2/items/V2ConversationItemTheme.kt | 9 + .../v2/items/V2ConversationItemThumbnail.kt | 252 ++++++++++++++++++ ...BodyUtil.kt => V2ConversationItemUtils.kt} | 9 +- .../v2/items/V2FooterPositionDelegate.kt | 3 +- .../v2_conversation_item_thumbnail_stub.xml | 3 +- .../ConversationItemTest_linkifyUrlLinks.kt | 4 +- 10 files changed, 284 insertions(+), 160 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemThumbnail.kt rename app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/{V2ConversationBodyUtil.kt => V2ConversationItemUtils.kt} (81%) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java index 4dfffb7b1e..3215077cdf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -96,7 +96,7 @@ import org.thoughtcrime.securesms.conversation.mutiselect.MultiselectCollection; import org.thoughtcrime.securesms.conversation.mutiselect.MultiselectPart; import org.thoughtcrime.securesms.conversation.ui.payment.PaymentMessageView; import org.thoughtcrime.securesms.conversation.v2.items.InteractiveConversationElement; -import org.thoughtcrime.securesms.conversation.v2.items.V2ConversationBodyUtil; +import org.thoughtcrime.securesms.conversation.v2.items.V2ConversationItemUtils; import org.thoughtcrime.securesms.database.AttachmentTable; import org.thoughtcrime.securesms.database.MediaTable; import org.thoughtcrime.securesms.database.MessageTable; @@ -1529,7 +1529,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo private void linkifyMessageBody(@NonNull Spannable messageBody, boolean shouldLinkifyAllLinks) { - V2ConversationBodyUtil.linkifyUrlLinks(messageBody, shouldLinkifyAllLinks, urlClickListener); + V2ConversationItemUtils.linkifyUrlLinks(messageBody, shouldLinkifyAllLinks, urlClickListener); if (conversationMessage.hasStyleLinks()) { for (PlaceholderURLSpan placeholder : messageBody.getSpans(0, messageBody.length(), PlaceholderURLSpan.class)) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemMediaBindingBridge.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemMediaBindingBridge.kt index 5cd7a0420e..1302df935f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemMediaBindingBridge.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemMediaBindingBridge.kt @@ -5,7 +5,6 @@ package org.thoughtcrime.securesms.conversation.v2.items -import android.widget.ImageView import android.widget.Space import org.thoughtcrime.securesms.components.QuoteView import org.thoughtcrime.securesms.databinding.V2ConversationItemMediaIncomingBinding @@ -20,7 +19,7 @@ import org.thoughtcrime.securesms.util.views.Stub */ data class V2ConversationItemMediaBindingBridge( val textBridge: V2ConversationItemTextOnlyBindingBridge, - val thumbnailStub: Stub, + val thumbnailStub: Stub, val quoteStub: Stub, val bodyContentSpacer: Space ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemMediaViewHolder.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemMediaViewHolder.kt index 9f33c8031b..0aabc74964 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemMediaViewHolder.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemMediaViewHolder.kt @@ -5,20 +5,12 @@ package org.thoughtcrime.securesms.conversation.v2.items -import android.graphics.drawable.Drawable import android.util.TypedValue import android.view.View -import android.widget.ImageView -import androidx.core.view.updateLayoutParams -import com.bumptech.glide.request.target.CustomViewTarget -import com.bumptech.glide.request.transition.Transition -import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.QuoteView import org.thoughtcrime.securesms.conversation.v2.data.ConversationMessageElement import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord import org.thoughtcrime.securesms.keyvalue.SignalStore -import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader -import org.thoughtcrime.securesms.mms.Slide import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel import org.thoughtcrime.securesms.util.changeConstraints @@ -37,10 +29,6 @@ class V2ConversationItemMediaViewHolder>( V2FooterPositionDelegate(binding) ) { - private var thumbnailSlide: Slide? = null - private var placeholderTarget: PlaceholderTarget? = null - private val thumbnailSize = intArrayOf(0, 0) - init { binding.textBridge.conversationItemBodyWrapper.clipToOutline = true } @@ -64,7 +52,7 @@ class V2ConversationItemMediaViewHolder>( binding.textBridge.root.changeConstraints { val maxBodyWidth = if (hasThumbnail()) { - thumbnailSize[0] + binding.thumbnailStub.get().thumbWidth } else { 0 } @@ -128,125 +116,12 @@ class V2ConversationItemMediaViewHolder>( } private fun presentThumbnail() { - val slideDeck = requireMediaMessage().slideDeck - if (slideDeck.thumbnailSlides.isEmpty() || slideDeck.thumbnailSlides.size > 1) { - binding.thumbnailStub.visibility = View.GONE - thumbnailSize[0] = -1 - thumbnailSize[1] = -1 - - return + if (binding.thumbnailStub.resolved() || requireMediaMessage().slideDeck.thumbnailSlides.size == 1) { + binding.thumbnailStub.get().presentThumbnail( + mediaMessage = requireMediaMessage(), + conversationContext = conversationContext + ) } - - binding.thumbnailStub.visibility = View.VISIBLE - - val thumbnail = slideDeck.thumbnailSlides.first() - - // TODO [alex] -- Is this correct? - if (thumbnail == thumbnailSlide) { - return - } - - thumbnailSlide = thumbnail - - conversationContext.glideRequests.clear(binding.thumbnailStub.get()) - - if (placeholderTarget != null) { - conversationContext.glideRequests.clear(placeholderTarget) - } - // endif - - val thumbnailUri = thumbnail.uri - val thumbnailBlur = thumbnail.placeholderBlur - - val thumbnailAttachment = thumbnail.asAttachment() - val thumbnailWidth = thumbnailAttachment.width - val thumbnailHeight = thumbnailAttachment.height - - val maxWidth = context.resources.getDimensionPixelSize(R.dimen.media_bubble_max_width) - val maxHeight = context.resources.getDimensionPixelSize(R.dimen.media_bubble_max_height) - - setThumbnailSize( - thumbnailWidth, - thumbnailHeight, - maxWidth, - maxHeight - ) - - binding.thumbnailStub.get().updateLayoutParams { - width = thumbnailSize[0] - height = thumbnailSize[1] - } - - if (thumbnailBlur != null) { - val placeholderTarget = PlaceholderTarget(binding.thumbnailStub.get()) - conversationContext - .glideRequests - .load(thumbnailBlur) - .centerInside() - .dontAnimate() - .override(thumbnailSize[0], thumbnailSize[1]) - .into(placeholderTarget) - - this.placeholderTarget = placeholderTarget - } - - if (thumbnailUri != null) { - conversationContext - .glideRequests - .load(DecryptableStreamUriLoader.DecryptableUri(thumbnailUri)) - .centerInside() - .dontAnimate() - .override(thumbnailSize[0], thumbnailSize[1]) - .into(binding.thumbnailStub.get()) - } - } - - private fun setThumbnailSize( - thumbnailWidth: Int, - thumbnailHeight: Int, - maxWidth: Int, - maxHeight: Int - ) { - if (thumbnailWidth == 0 || thumbnailHeight == 0) { - thumbnailSize[0] = maxWidth - thumbnailSize[1] = maxHeight - return - } - - if (thumbnailWidth <= maxWidth && thumbnailHeight <= maxHeight) { - thumbnailSize[0] = thumbnailWidth - thumbnailSize[1] = thumbnailHeight - return - } - - if (thumbnailWidth > maxWidth) { - val thumbnailScale = 1 - ((thumbnailWidth - maxWidth) / thumbnailWidth.toFloat()) - - thumbnailSize[0] = (thumbnailWidth * thumbnailScale).toInt() - thumbnailSize[1] = (thumbnailHeight * thumbnailScale).toInt() - } - - if (isThumbnailMetricsSatisfied(maxWidth, maxHeight)) { - return - } - - if (thumbnailHeight > maxHeight) { - val thumbnailScale = 1 - ((thumbnailHeight - maxHeight) / thumbnailHeight.toFloat()) - - thumbnailSize[0] = (thumbnailWidth * thumbnailScale).toInt() - thumbnailSize[1] = (thumbnailHeight * thumbnailScale).toInt() - } - - if (isThumbnailMetricsSatisfied(maxWidth, maxHeight)) { - return - } - - setThumbnailSize( - thumbnailSize[0], - thumbnailSize[1], - maxWidth, - maxHeight - ) } private fun hasGroupSenderName(): Boolean { @@ -265,25 +140,7 @@ class V2ConversationItemMediaViewHolder>( return hasThumbnail() || hasQuote() } - private fun isThumbnailMetricsSatisfied(maxWidth: Int, maxHeight: Int): Boolean { - return thumbnailSize[0] in 1..maxWidth && thumbnailSize[1] in 1..maxHeight - } - private fun requireMediaMessage(): MediaMmsMessageRecord { return conversationMessage.messageRecord as MediaMmsMessageRecord } - - private inner class PlaceholderTarget(view: ImageView) : CustomViewTarget(view) { - override fun onLoadFailed(errorDrawable: Drawable?) { - view.background = errorDrawable - } - - override fun onResourceCleared(placeholder: Drawable?) { - view.background = placeholder - } - - override fun onResourceReady(resource: Drawable, transition: Transition?) { - view.background = resource - } - } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder.kt index f18c95a0fa..79ceade5e0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTextOnlyViewHolder.kt @@ -355,7 +355,7 @@ open class V2ConversationItemTextOnlyViewHolder>( } private fun linkifyMessageBody(messageBody: Spannable) { - V2ConversationBodyUtil.linkifyUrlLinks(messageBody, conversationContext.selectedItems.isEmpty(), conversationContext.clickListener::onUrlClicked) + V2ConversationItemUtils.linkifyUrlLinks(messageBody, conversationContext.selectedItems.isEmpty(), conversationContext.clickListener::onUrlClicked) if (conversationMessage.hasStyleLinks()) { messageBody.getSpans(0, messageBody.length, PlaceholderURLSpan::class.java).forEach { placeholder -> diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme.kt index 930830fc24..5935a87355 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemTheme.kt @@ -11,6 +11,7 @@ import androidx.annotation.ColorInt import androidx.core.content.ContextCompat import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.conversation.ConversationMessage +import org.thoughtcrime.securesms.conversation.v2.items.V2ConversationItemUtils.isThumbnailAtBottomOfBubble import org.thoughtcrime.securesms.util.hasNoBubble /** @@ -34,6 +35,10 @@ class V2ConversationItemTheme( fun getFooterIconColor( conversationMessage: ConversationMessage ): Int { + if (conversationMessage.messageRecord.isThumbnailAtBottomOfBubble(context)) { + return ContextCompat.getColor(context, R.color.signal_colorOnCustom) + } + return getColor( conversationMessage, conversationContext.getColorizer()::getOutgoingFooterIconColor, @@ -45,6 +50,10 @@ class V2ConversationItemTheme( fun getFooterTextColor( conversationMessage: ConversationMessage ): Int { + if (conversationMessage.messageRecord.isThumbnailAtBottomOfBubble(context)) { + return ContextCompat.getColor(context, R.color.signal_colorOnCustom) + } + return getColor( conversationMessage, conversationContext.getColorizer()::getOutgoingFooterTextColor, diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemThumbnail.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemThumbnail.kt new file mode 100644 index 0000000000..aafde5327b --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemThumbnail.kt @@ -0,0 +1,252 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.conversation.v2.items + +import android.content.Context +import android.graphics.Canvas +import android.graphics.LinearGradient +import android.graphics.Paint +import android.graphics.Rect +import android.graphics.Shader +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import android.util.Size +import android.view.View +import android.widget.ImageView +import androidx.appcompat.widget.AppCompatImageView +import androidx.core.graphics.withTranslation +import androidx.core.view.updateLayoutParams +import com.bumptech.glide.request.target.CustomViewTarget +import com.bumptech.glide.request.transition.Transition +import org.signal.core.util.dp +import org.thoughtcrime.securesms.R +import org.thoughtcrime.securesms.conversation.v2.items.V2ConversationItemUtils.isThumbnailAtBottomOfBubble +import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord +import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader +import org.thoughtcrime.securesms.mms.Slide + +/** + * ImageView subclass that adds support for a foreground drawable and + * gradient at the bottom, rendered in onDrawForeground. + * + * This is lighter weight then adding a bunch of extra, possibly unnecessary views + * to the relevant layouts. + * + * Also encapsulates the logic around presenting thumbnails to the user. + */ +class V2ConversationItemThumbnail @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null +) : AppCompatImageView(context, attrs) { + + companion object { + private val FOREGROUND_SHADE_HEIGHT = 32.dp + private val UNSET_SIZE = Size(-1, -1) + private const val MAX_SIZE_RECURSION_DEPTH = 5 + } + + private val gradientPaint = Paint().apply { + isAntiAlias = true + } + + private val rect = Rect() + private var drawForegroundShade: Boolean = true + private var compatForegroundDrawable: Drawable? = null + + private var thumbnailSlide: Slide? = null + private var fastPreflightId: String? = null + + private var placeholderTarget: PlaceholderTarget? = null + private var thumbnailSize = UNSET_SIZE + + val thumbWidth: Int get() = thumbnailSize.width + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + gradientPaint.shader = LinearGradient( + w / 2f, + 0f, + w / 2f, + FOREGROUND_SHADE_HEIGHT.toFloat(), + intArrayOf(0x00000000, 0x88000000.toInt()), + floatArrayOf(0f, 1f), + Shader.TileMode.CLAMP + ) + } + + override fun onDrawForeground(canvas: Canvas) { + super.onDrawForeground(canvas) + + canvas.getClipBounds(rect) + + if (drawForegroundShade) { + canvas.withTranslation(y = rect.height() - FOREGROUND_SHADE_HEIGHT.toFloat()) { + canvas.drawPaint(gradientPaint) + } + } + + // Sizing? + compatForegroundDrawable?.draw(canvas) + } + + fun presentThumbnail( + mediaMessage: MediaMmsMessageRecord, + conversationContext: V2ConversationContext + ) { + val slideDeck = mediaMessage.slideDeck + if (slideDeck.thumbnailSlides.isEmpty() || slideDeck.thumbnailSlides.size > 1) { + visibility = View.GONE + thumbnailSize = UNSET_SIZE + + return + } + + visibility = View.VISIBLE + + val thumbnail = slideDeck.thumbnailSlides.first() + val fastPreflightId = slideDeck.thumbnailSlides.first().fastPreflightId + + if (thumbnail == thumbnailSlide && fastPreflightId == this.fastPreflightId) { + return + } + + thumbnailSlide = thumbnail + this.fastPreflightId = fastPreflightId + + conversationContext.glideRequests.clear(this) + + if (placeholderTarget != null) { + conversationContext.glideRequests.clear(placeholderTarget) + } + + val thumbnailUri = thumbnail.uri + val thumbnailBlur = thumbnail.placeholderBlur + + val thumbnailAttachment = thumbnail.asAttachment() + val thumbnailWidth = thumbnailAttachment.width + val thumbnailHeight = thumbnailAttachment.height + + val maxWidth = context.resources.getDimensionPixelSize(R.dimen.media_bubble_max_width) + val maxHeight = context.resources.getDimensionPixelSize(R.dimen.media_bubble_max_height) + + setThumbnailSize( + thumbnailWidth, + thumbnailHeight, + maxWidth, + maxHeight, + 0 + ) + + updateLayoutParams { + width = thumbnailSize.width + height = thumbnailSize.height + } + + if (thumbnailBlur != null) { + val placeholderTarget = PlaceholderTarget(this) + conversationContext + .glideRequests + .load(thumbnailBlur) + .centerInside() + .dontAnimate() + .override(thumbnailSize.width, thumbnailSize.height) + .into(placeholderTarget) + + this.placeholderTarget = placeholderTarget + } + + if (thumbnailUri != null) { + conversationContext + .glideRequests + .load(DecryptableStreamUriLoader.DecryptableUri(thumbnailUri)) + .centerInside() + .dontAnimate() + .override(thumbnailSize.width, thumbnailSize.height) + .into(this) + } + + setDrawForegroundShade(mediaMessage.isThumbnailAtBottomOfBubble(context)) + } + + private fun setDrawForegroundShade(drawForegroundShade: Boolean) { + this.drawForegroundShade = drawForegroundShade + invalidate() + } + + private fun setCompatForegroundDrawable(drawable: Drawable?) { + this.compatForegroundDrawable = drawable + invalidate() + } + + private fun setThumbnailSize( + thumbnailWidth: Int, + thumbnailHeight: Int, + maxWidth: Int, + maxHeight: Int, + depth: Int + ) { + if (thumbnailWidth == 0 || thumbnailHeight == 0 || depth >= MAX_SIZE_RECURSION_DEPTH) { + thumbnailSize = Size(maxWidth, maxHeight) + return + } + + if (thumbnailWidth <= maxWidth && thumbnailHeight <= maxHeight) { + thumbnailSize = Size(thumbnailWidth, thumbnailHeight) + return + } + + if (thumbnailWidth > maxWidth) { + val thumbnailScale = 1 - ((thumbnailWidth - maxWidth) / thumbnailWidth.toFloat()) + + thumbnailSize = Size( + (thumbnailWidth * thumbnailScale).toInt(), + (thumbnailHeight * thumbnailScale).toInt() + ) + } + + if (isThumbnailMetricsSatisfied(maxWidth, maxHeight)) { + return + } + + if (thumbnailHeight > maxHeight) { + val thumbnailScale = 1 - ((thumbnailHeight - maxHeight) / thumbnailHeight.toFloat()) + + thumbnailSize = Size( + (thumbnailWidth * thumbnailScale).toInt(), + (thumbnailHeight * thumbnailScale).toInt() + ) + } + + if (isThumbnailMetricsSatisfied(maxWidth, maxHeight)) { + return + } + + setThumbnailSize( + thumbnailSize.width, + thumbnailSize.height, + maxWidth, + maxHeight, + depth + 1 + ) + } + + private fun isThumbnailMetricsSatisfied(maxWidth: Int, maxHeight: Int): Boolean { + return thumbnailSize.width in 1..maxWidth && thumbnailSize.height in 1..maxHeight + } + + private class PlaceholderTarget(view: ImageView) : CustomViewTarget(view) { + override fun onLoadFailed(errorDrawable: Drawable?) { + view.background = errorDrawable + } + + override fun onResourceCleared(placeholder: Drawable?) { + view.background = placeholder + } + + override fun onResourceReady(resource: Drawable, transition: Transition?) { + view.background = resource + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationBodyUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemUtils.kt similarity index 81% rename from app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationBodyUtil.kt rename to app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemUtils.kt index 987475db6a..7a395978a3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationBodyUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemUtils.kt @@ -5,19 +5,26 @@ package org.thoughtcrime.securesms.conversation.v2.items +import android.content.Context import android.text.Spannable import android.text.Spanned import android.text.style.URLSpan import android.text.util.Linkify import androidx.core.text.util.LinkifyCompat +import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.util.InterceptableLongClickCopyLinkSpan import org.thoughtcrime.securesms.util.LinkUtil import org.thoughtcrime.securesms.util.UrlClickHandler +import org.thoughtcrime.securesms.util.hasOnlyThumbnail /** * Utilities for presenting the body of a conversation message. */ -object V2ConversationBodyUtil { +object V2ConversationItemUtils { + + fun MessageRecord.isThumbnailAtBottomOfBubble(context: Context): Boolean { + return hasOnlyThumbnail(context) && isDisplayBodyEmpty(context) + } @JvmStatic fun linkifyUrlLinks(messageBody: Spannable, shouldLinkifyAllLinks: Boolean, urlClickHandler: UrlClickHandler) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate.kt index 0182c79a3a..75d1c2b9e9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2FooterPositionDelegate.kt @@ -6,7 +6,6 @@ package org.thoughtcrime.securesms.conversation.v2.items import android.view.View -import android.widget.ImageView import org.signal.core.util.dp import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.emoji.EmojiTextView @@ -24,7 +23,7 @@ class V2FooterPositionDelegate private constructor( private val footerViews: List, private val bodyContainer: View, private val body: EmojiTextView, - private val thumbnailView: Stub? + private val thumbnailView: Stub? ) : V2ConversationItemLayout.OnMeasureListener { constructor(binding: V2ConversationItemTextOnlyBindingBridge) : this( diff --git a/app/src/main/res/layout/v2_conversation_item_thumbnail_stub.xml b/app/src/main/res/layout/v2_conversation_item_thumbnail_stub.xml index 0935efb6b7..d61033824c 100644 --- a/app/src/main/res/layout/v2_conversation_item_thumbnail_stub.xml +++ b/app/src/main/res/layout/v2_conversation_item_thumbnail_stub.xml @@ -2,7 +2,8 @@ ~ Copyright 2023 Signal Messenger, LLC ~ SPDX-License-Identifier: AGPL-3.0-only --> -