diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index d6a8779f82..a41a2c3736 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -560,29 +560,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } override fun inputBarHeightChanged(newValue: Int) { - @Suppress("NAME_SHADOWING") val newValue = max(newValue, resources.getDimension(R.dimen.input_bar_height).roundToInt()) - // 36 DP is the exact height of the typing indicator view. It's also exactly 18 * 2, and 18 is the large message - // corner radius. This makes 36 DP look "correct" in the context of other messages on the screen. - val typingIndicatorHeight = if (binding.typingIndicatorViewContainer.isVisible) toPx(36, resources) else 0 - // Recycler view - val recyclerViewLayoutParams = binding.conversationRecyclerView.layoutParams as RelativeLayout.LayoutParams - recyclerViewLayoutParams.bottomMargin = newValue + typingIndicatorHeight - binding.conversationRecyclerView.layoutParams = recyclerViewLayoutParams - // Additional content container - val additionalContentContainerLayoutParams = binding.additionalContentContainer.layoutParams as RelativeLayout.LayoutParams - additionalContentContainerLayoutParams.bottomMargin = newValue - binding.additionalContentContainer.layoutParams = additionalContentContainerLayoutParams - // Attachment options - val attachmentButtonHeight = binding.inputBar.attachmentButtonsContainerHeight - val bottomMargin = (newValue - binding.inputBar.additionalContentHeight - attachmentButtonHeight) / 2 - val margin = toPx(8, resources) - val attachmentOptionsContainerLayoutParams = binding.attachmentOptionsContainer.layoutParams as RelativeLayout.LayoutParams - attachmentOptionsContainerLayoutParams.bottomMargin = bottomMargin + attachmentButtonHeight + margin - binding.attachmentOptionsContainer.layoutParams = attachmentOptionsContainerLayoutParams - // Scroll to bottom button - val scrollToBottomButtonLayoutParams = binding.scrollToBottomButton.layoutParams as RelativeLayout.LayoutParams - scrollToBottomButtonLayoutParams.bottomMargin = newValue + binding.additionalContentContainer.height + toPx(12, resources) - binding.scrollToBottomButton.layoutParams = scrollToBottomButtonLayoutParams } override fun inputBarEditTextContentChanged(newContent: CharSequence) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt index cfa7fb08a6..6e0ea32fa4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt @@ -82,15 +82,6 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li } // endregion - // region General - private fun setHeight(newHeight: Int) { - val layoutParams = binding.inputBarLinearLayout.layoutParams as LayoutParams - layoutParams.height = newHeight - binding.inputBarLinearLayout.layoutParams = layoutParams - delegate?.inputBarHeightChanged(newHeight) - } - // endregion - // region Updating override fun inputBarEditTextContentChanged(text: CharSequence) { sendButton.isVisible = text.isNotEmpty() @@ -99,8 +90,6 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li } override fun inputBarEditTextHeightChanged(newValue: Int) { - val newHeight = max(newValue + 2 * vMargin, minHeight) + binding.inputBarAdditionalContentContainer.height - setHeight(newHeight) } override fun commitInputContent(contentUri: Uri) { @@ -127,40 +116,26 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li quoteView.delegate = this binding.inputBarAdditionalContentContainer.addView(quoteView) val attachments = (message as? MmsMessageRecord)?.slideDeck - // The max content width is the screen width - 2 times the horizontal input bar padding - the - // quote view content area's start and end margins. This unfortunately has to be calculated manually - // here to get the layout right. - val maxContentWidth = (screenWidth - 2 * resources.getDimension(R.dimen.medium_spacing) - toPx(16, resources) - toPx(30, resources)).roundToInt() val sender = if (message.isOutgoing) TextSecurePreferences.getLocalNumber(context)!! else message.individualRecipient.address.serialize() quoteView.bind(sender, message.body, attachments, - thread, true, maxContentWidth, message.isOpenGroupInvitation, message.threadId, false, glide) - // The 6 DP below is the padding the quote view applies to itself, which isn't included in the - // intrinsic height calculation. - val quoteViewIntrinsicHeight = quoteView.getIntrinsicHeight(maxContentWidth) + toPx(6, resources) - val newHeight = max(binding.inputBarEditText.height + 2 * vMargin, minHeight) + quoteViewIntrinsicHeight - additionalContentHeight = quoteViewIntrinsicHeight - setHeight(newHeight) + thread, true, message.isOpenGroupInvitation, message.threadId, false, glide) + requestLayout() } override fun cancelQuoteDraft() { quote = null binding.inputBarAdditionalContentContainer.removeAllViews() - val newHeight = max(binding.inputBarEditText.height + 2 * vMargin, minHeight) - additionalContentHeight = 0 - setHeight(newHeight) + requestLayout() } fun draftLinkPreview() { quote = null - val linkPreviewDraftHeight = toPx(88, resources) binding.inputBarAdditionalContentContainer.removeAllViews() val linkPreviewDraftView = LinkPreviewDraftView(context) linkPreviewDraftView.delegate = this this.linkPreviewDraftView = linkPreviewDraftView binding.inputBarAdditionalContentContainer.addView(linkPreviewDraftView) - val newHeight = max(binding.inputBarEditText.height + 2 * vMargin, minHeight) + linkPreviewDraftHeight - additionalContentHeight = linkPreviewDraftHeight - setHeight(newHeight) + requestLayout() } fun updateLinkPreviewDraft(glide: GlideRequests, linkPreview: LinkPreview) { @@ -173,9 +148,7 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li if (quote != null) { return } linkPreview = null binding.inputBarAdditionalContentContainer.removeAllViews() - val newHeight = max(binding.inputBarEditText.height + 2 * vMargin, minHeight) - additionalContentHeight = 0 - setHeight(newHeight) + requestLayout() } private fun showOrHideInputIfNeeded() { 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 7c23ca1435..3df12a5160 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 @@ -2,10 +2,10 @@ package org.thoughtcrime.securesms.conversation.v2.messages import android.content.Context import android.content.res.ColorStateList +import android.text.StaticLayout import android.util.AttributeSet import android.view.LayoutInflater import android.widget.LinearLayout -import android.widget.RelativeLayout import androidx.annotation.ColorInt import androidx.core.content.res.ResourcesCompat import androidx.core.text.toSpannable @@ -18,6 +18,8 @@ import org.session.libsession.utilities.recipients.Recipient import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities import org.thoughtcrime.securesms.database.SessionContactDatabase +import org.thoughtcrime.securesms.database.model.Quote +import org.thoughtcrime.securesms.database.model.ThreadRecord import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.mms.SlideDeck import org.thoughtcrime.securesms.util.MediaUtil @@ -26,7 +28,6 @@ import org.thoughtcrime.securesms.util.toPx import javax.inject.Inject import kotlin.math.max import kotlin.math.min -import kotlin.math.roundToInt // There's quite some calculation going on here. It's a bit complex so don't make changes // if you don't need to. If you do then test: @@ -61,10 +62,6 @@ class QuoteView : LinearLayout { Mode.Regular -> { binding.quoteViewCancelButton.isVisible = false binding.mainQuoteViewContainer.setBackgroundColor(ResourcesCompat.getColor(resources, R.color.transparent, context.theme)) - val quoteViewMainContentContainerLayoutParams = binding.quoteViewMainContentContainer.layoutParams as RelativeLayout.LayoutParams - // Since we're not showing the cancel button we can shorten the end margin - quoteViewMainContentContainerLayoutParams.marginEnd = resources.getDimension(R.dimen.medium_spacing).roundToInt() - // binding.quoteViewMainContentContainer.layoutParams = quoteViewMainContentContainerLayoutParams } } } @@ -75,7 +72,7 @@ class QuoteView : LinearLayout { // If we're showing an attachment thumbnail, just constrain to the height of that if (binding.quoteViewAttachmentPreviewContainer.isVisible) { return toPx(40, resources) } var result = 0 - var authorTextViewIntrinsicHeight = 0 + val authorTextViewIntrinsicHeight: Int if (binding.quoteViewAuthorTextView.isVisible) { val author = binding.quoteViewAuthorTextView.text authorTextViewIntrinsicHeight = TextUtilities.getIntrinsicHeight(author, binding.quoteViewAuthorTextView.paint, maxContentWidth) @@ -110,7 +107,7 @@ class QuoteView : LinearLayout { // region Updating fun bind(authorPublicKey: String, body: String?, attachments: SlideDeck?, thread: Recipient, - isOutgoingMessage: Boolean, maxContentWidth: Int, isOpenGroupInvitation: Boolean, threadID: Long, + isOutgoingMessage: Boolean, isOpenGroupInvitation: Boolean, threadID: Long, isOriginalMissing: Boolean, glide: GlideRequests) { // Reduce the max body text view line count to 2 if this is a group thread because // we'll be showing the author text view and we don't want the overall quote view height @@ -125,16 +122,13 @@ class QuoteView : LinearLayout { } binding.quoteViewAuthorTextView.isVisible = thread.isGroupRecipient // Body - binding.quoteViewBodyTextView.text = if (isOpenGroupInvitation) resources.getString(R.string.open_group_invitation_view__open_group_invitation) else MentionUtilities.highlightMentions((body ?: "").toSpannable(), threadID, context); + binding.quoteViewBodyTextView.text = if (isOpenGroupInvitation) resources.getString(R.string.open_group_invitation_view__open_group_invitation) else MentionUtilities.highlightMentions((body ?: "").toSpannable(), threadID, context) binding.quoteViewBodyTextView.setTextColor(getTextColor(isOutgoingMessage)) // Accent line / attachment preview val hasAttachments = (attachments != null && attachments.asAttachments().isNotEmpty()) && !isOriginalMissing binding.quoteViewAccentLine.isVisible = !hasAttachments binding.quoteViewAttachmentPreviewContainer.isVisible = hasAttachments if (!hasAttachments) { - val accentLineLayoutParams = binding.quoteViewAccentLine.layoutParams as RelativeLayout.LayoutParams - accentLineLayoutParams.height = getIntrinsicContentHeight(maxContentWidth) // Match the intrinsic * content * height - // binding.quoteViewAccentLine.layoutParams = accentLineLayoutParams binding.quoteViewAccentLine.setBackgroundColor(getLineColor(isOutgoingMessage)) } else if (attachments != null) { binding.quoteViewAttachmentPreviewImageView.imageTintList = ColorStateList.valueOf(ResourcesCompat.getColor(resources, R.color.white, context.theme)) @@ -164,11 +158,6 @@ class QuoteView : LinearLayout { } } } - //mainQuoteViewContainer.layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, getIntrinsicHeight(maxContentWidth)) -// val quoteViewMainContentContainerLayoutParams = quoteViewMainContentContainer.layoutParams as RelativeLayout.LayoutParams - // The start margin is different if we just show the accent line vs if we show an attachment thumbnail -// quoteViewMainContentContainerLayoutParams.marginStart = if (!hasAttachments) toPx(16, resources) else toPx(48, resources) -// quoteViewMainContentContainer.layoutParams = quoteViewMainContentContainerLayoutParams } // endregion @@ -201,6 +190,31 @@ class QuoteView : LinearLayout { ResourcesCompat.getColor(resources, R.color.white, context.theme) } } + + fun calculateWidth(quote: Quote, bodyWidth: Int, maxContentWidth: Int, thread: Recipient): Int { + binding.quoteViewAuthorTextView.isVisible = thread.isGroupRecipient + var paddingWidth = resources.getDimensionPixelSize(R.dimen.medium_spacing) * 5 // initial horizontal padding + with (binding) { + if (quoteViewAttachmentPreviewContainer.isVisible) { + paddingWidth += toPx(40, resources) + } + if (quoteViewAccentLine.isVisible) { + paddingWidth += resources.getDimensionPixelSize(R.dimen.accent_line_thickness) + } + } + val quoteBodyWidth = StaticLayout.getDesiredWidth(binding.quoteViewBodyTextView.text, binding.quoteViewBodyTextView.paint).toInt() + paddingWidth + + val quoteAuthorWidth = if (thread.isGroupRecipient) { + val authorPublicKey = quote.author.serialize() + val author = contactDb.getContactWithSessionID(authorPublicKey) + val authorDisplayName = author?.displayName(Contact.contextForRecipient(thread)) ?: authorPublicKey + StaticLayout.getDesiredWidth(authorDisplayName, binding.quoteViewBodyTextView.paint).toInt() + paddingWidth + } else 0 + + val quoteWidth = max(quoteBodyWidth, quoteAuthorWidth) + val usedWidth = max(quoteWidth, bodyWidth) + return min(maxContentWidth, usedWidth) + } // endregion } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt index af0e6578a0..7b1b06be24 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt @@ -5,6 +5,7 @@ import android.graphics.Color import android.graphics.Rect import android.graphics.drawable.Drawable import android.text.Spannable +import android.text.StaticLayout import android.text.style.BackgroundColorSpan import android.text.style.ForegroundColorSpan import android.text.style.URLSpan @@ -12,6 +13,7 @@ import android.text.util.Linkify import android.util.AttributeSet import android.view.LayoutInflater import android.view.MotionEvent +import android.view.View import android.view.ViewGroup import android.widget.LinearLayout import androidx.annotation.ColorInt @@ -41,7 +43,7 @@ import org.thoughtcrime.securesms.util.SearchUtil import org.thoughtcrime.securesms.util.UiModeUtilities import org.thoughtcrime.securesms.util.getColorWithID import org.thoughtcrime.securesms.util.toPx -import java.util.Locale +import java.util.* import kotlin.math.roundToInt class VisibleMessageContentView : LinearLayout { @@ -89,9 +91,6 @@ class VisibleMessageContentView : LinearLayout { } binding.quoteView.isVisible = message is MmsMessageRecord && message.quote != null - val quoteLayoutParams = binding.quoteView.layoutParams - quoteLayoutParams.width = if (mediaThumbnailMessage) 0 else ViewGroup.LayoutParams.WRAP_CONTENT - binding.quoteView.layoutParams = quoteLayoutParams binding.linkPreviewView.isVisible = message is MmsMessageRecord && message.linkPreviews.isNotEmpty() @@ -120,7 +119,7 @@ class VisibleMessageContentView : LinearLayout { quote.text } binding.quoteView.bind(quote.author.toString(), quoteText, quote.attachment, thread, - message.isOutgoing, maxContentWidth, message.isOpenGroupInvitation, message.threadId, + message.isOutgoing, message.isOpenGroupInvitation, message.threadId, quote.isOriginalMissing, glide) onContentClick.add { event -> val r = Rect() @@ -192,8 +191,21 @@ class VisibleMessageContentView : LinearLayout { // set it to use constraints if not only a text message, otherwise wrap content to whatever width it wants val params = binding.bodyTextView.layoutParams - params.width = if (onlyBodyMessage) ViewGroup.LayoutParams.WRAP_CONTENT else 0 + params.width = if (onlyBodyMessage || binding.barrierViewsGone()) ViewGroup.LayoutParams.WRAP_CONTENT else 0 binding.bodyTextView.layoutParams = params + binding.bodyTextView.maxWidth = maxWidth + + val bodyWidth = with (binding.bodyTextView) { + StaticLayout.getDesiredWidth(text, paint).roundToInt() + } + + val quote = (message as? MmsMessageRecord)?.quote + val quoteLayoutParams = binding.quoteView.layoutParams + quoteLayoutParams.width = + if (mediaThumbnailMessage || quote == null) 0 + else binding.quoteView.calculateWidth(quote, bodyWidth, maxWidth, thread) + + binding.quoteView.layoutParams = quoteLayoutParams if (message.body.isNotEmpty() && !hideBody) { val color = getTextColor(context, message) @@ -209,6 +221,9 @@ class VisibleMessageContentView : LinearLayout { } } + private fun ViewVisibleMessageContentBinding.barrierViewsGone(): Boolean = + listOf(albumThumbnailView, linkPreviewView, voiceMessageView, quoteView).none { it.isVisible } + private fun getBackground(isOutgoing: Boolean, isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean): Drawable { val isSingleMessage = (isStartOfMessageCluster && isEndOfMessageCluster) @DrawableRes val backgroundID = when { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt index bcc9e31ba7..38723d2390 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt @@ -145,13 +145,13 @@ class VisibleMessageView : LinearLayout { binding.messageTimestampTextView.text = DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), message.timestamp) // Margins val startPadding = if (isGroupThread) { - if (message.isOutgoing) resources.getDimension(R.dimen.very_large_spacing).toInt() else 0 + if (message.isOutgoing) resources.getDimensionPixelSize(R.dimen.very_large_spacing) else toPx(50,resources) } else { - if (message.isOutgoing) resources.getDimension(R.dimen.very_large_spacing).toInt() - else resources.getDimension(R.dimen.medium_spacing).toInt() + if (message.isOutgoing) resources.getDimensionPixelSize(R.dimen.very_large_spacing) + else resources.getDimensionPixelSize(R.dimen.medium_spacing) } - val endPadding = if (message.isOutgoing) resources.getDimension(R.dimen.medium_spacing).toInt() - else resources.getDimension(R.dimen.very_large_spacing).toInt() + val endPadding = if (message.isOutgoing) resources.getDimensionPixelSize(R.dimen.medium_spacing) + else resources.getDimensionPixelSize(R.dimen.very_large_spacing) binding.messageContentContainer.setPaddingRelative(startPadding, 0, endPadding, 0) // Set inter-message spacing setMessageSpacing(isStartOfMessageCluster, isEndOfMessageCluster) diff --git a/app/src/main/res/layout/activity_conversation_v2.xml b/app/src/main/res/layout/activity_conversation_v2.xml index 3309a648f9..65652359c5 100644 --- a/app/src/main/res/layout/activity_conversation_v2.xml +++ b/app/src/main/res/layout/activity_conversation_v2.xml @@ -16,17 +16,17 @@ + android:layout_height="match_parent" /> + android:layout_above="@+id/inputBar" + /> + android:layout_marginBottom="32dp"> diff --git a/app/src/main/res/layout/view_input_bar.xml b/app/src/main/res/layout/view_input_bar.xml index 5bc0674088..2b5e1fef5c 100644 --- a/app/src/main/res/layout/view_input_bar.xml +++ b/app/src/main/res/layout/view_input_bar.xml @@ -3,7 +3,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/inputBarLinearLayout" android:layout_width="match_parent" - android:layout_height="@dimen/input_bar_height" + android:layout_height="wrap_content" android:orientation="vertical" android:background="@color/input_bar_background"> diff --git a/app/src/main/res/layout/view_quote.xml b/app/src/main/res/layout/view_quote.xml index 6956c4011f..fee333cd48 100644 --- a/app/src/main/res/layout/view_quote.xml +++ b/app/src/main/res/layout/view_quote.xml @@ -1,29 +1,40 @@ - + android:paddingVertical="@dimen/small_spacing"> + android:layout_marginVertical="4dp" + android:background="@color/text" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintHorizontal_bias="0" + app:layout_constraintEnd_toStartOf="@id/quoteStartBarrier" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + android:layout_marginVertical="@dimen/small_spacing" + android:background="@drawable/view_quote_attachment_preview_background" + app:layout_constraintHorizontal_bias="0" + app:layout_constraintEnd_toStartOf="@id/quoteStartBarrier" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + - + app:layout_constraintHorizontal_bias="0" + app:layout_constraintStart_toEndOf="@+id/quoteStartBarrier" + app:layout_constraintEnd_toStartOf="@id/quoteViewCancelButton" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + android:orientation="vertical" + android:layout_width="0dp" + android:layout_height="wrap_content"> + android:textStyle="bold" + tools:text="Spiderman" /> - + android:textSize="@dimen/small_font_size" + tools:text="@tools:sample/lorem/random" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/view_visible_message.xml b/app/src/main/res/layout/view_visible_message.xml index 2ed6af3a0c..2e734034e3 100644 --- a/app/src/main/res/layout/view_visible_message.xml +++ b/app/src/main/res/layout/view_visible_message.xml @@ -14,48 +14,35 @@ android:textStyle="bold" android:gravity="center" /> - - - + - + - - - - - - - - - + - + \ No newline at end of file diff --git a/app/src/main/res/layout/view_visible_message_content.xml b/app/src/main/res/layout/view_visible_message_content.xml index 56dd1e7e1d..06b7eb393c 100644 --- a/app/src/main/res/layout/view_visible_message_content.xml +++ b/app/src/main/res/layout/view_visible_message_content.xml @@ -59,11 +59,10 @@ 24dp 16dp 56dp + 120dp