Fix quote alignment (#837)

* refactor: use constraints in quote view

* refactor: layouts for quotes fixed

* fix: use the current text, which may be the type of attachment instead of the quote body
This commit is contained in:
Harris 2022-02-07 15:38:07 +11:00 committed by GitHub
parent d4424481b1
commit 561ce83aa4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 144 additions and 154 deletions

View File

@ -560,29 +560,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
} }
override fun inputBarHeightChanged(newValue: Int) { 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) { override fun inputBarEditTextContentChanged(newContent: CharSequence) {

View File

@ -82,15 +82,6 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
} }
// endregion // 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 // region Updating
override fun inputBarEditTextContentChanged(text: CharSequence) { override fun inputBarEditTextContentChanged(text: CharSequence) {
sendButton.isVisible = text.isNotEmpty() sendButton.isVisible = text.isNotEmpty()
@ -99,8 +90,6 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
} }
override fun inputBarEditTextHeightChanged(newValue: Int) { override fun inputBarEditTextHeightChanged(newValue: Int) {
val newHeight = max(newValue + 2 * vMargin, minHeight) + binding.inputBarAdditionalContentContainer.height
setHeight(newHeight)
} }
override fun commitInputContent(contentUri: Uri) { override fun commitInputContent(contentUri: Uri) {
@ -127,40 +116,26 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
quoteView.delegate = this quoteView.delegate = this
binding.inputBarAdditionalContentContainer.addView(quoteView) binding.inputBarAdditionalContentContainer.addView(quoteView)
val attachments = (message as? MmsMessageRecord)?.slideDeck 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() val sender = if (message.isOutgoing) TextSecurePreferences.getLocalNumber(context)!! else message.individualRecipient.address.serialize()
quoteView.bind(sender, message.body, attachments, quoteView.bind(sender, message.body, attachments,
thread, true, maxContentWidth, message.isOpenGroupInvitation, message.threadId, false, glide) thread, true, 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 requestLayout()
// 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)
} }
override fun cancelQuoteDraft() { override fun cancelQuoteDraft() {
quote = null quote = null
binding.inputBarAdditionalContentContainer.removeAllViews() binding.inputBarAdditionalContentContainer.removeAllViews()
val newHeight = max(binding.inputBarEditText.height + 2 * vMargin, minHeight) requestLayout()
additionalContentHeight = 0
setHeight(newHeight)
} }
fun draftLinkPreview() { fun draftLinkPreview() {
quote = null quote = null
val linkPreviewDraftHeight = toPx(88, resources)
binding.inputBarAdditionalContentContainer.removeAllViews() binding.inputBarAdditionalContentContainer.removeAllViews()
val linkPreviewDraftView = LinkPreviewDraftView(context) val linkPreviewDraftView = LinkPreviewDraftView(context)
linkPreviewDraftView.delegate = this linkPreviewDraftView.delegate = this
this.linkPreviewDraftView = linkPreviewDraftView this.linkPreviewDraftView = linkPreviewDraftView
binding.inputBarAdditionalContentContainer.addView(linkPreviewDraftView) binding.inputBarAdditionalContentContainer.addView(linkPreviewDraftView)
val newHeight = max(binding.inputBarEditText.height + 2 * vMargin, minHeight) + linkPreviewDraftHeight requestLayout()
additionalContentHeight = linkPreviewDraftHeight
setHeight(newHeight)
} }
fun updateLinkPreviewDraft(glide: GlideRequests, linkPreview: LinkPreview) { fun updateLinkPreviewDraft(glide: GlideRequests, linkPreview: LinkPreview) {
@ -173,9 +148,7 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
if (quote != null) { return } if (quote != null) { return }
linkPreview = null linkPreview = null
binding.inputBarAdditionalContentContainer.removeAllViews() binding.inputBarAdditionalContentContainer.removeAllViews()
val newHeight = max(binding.inputBarEditText.height + 2 * vMargin, minHeight) requestLayout()
additionalContentHeight = 0
setHeight(newHeight)
} }
private fun showOrHideInputIfNeeded() { private fun showOrHideInputIfNeeded() {

View File

@ -2,10 +2,10 @@ package org.thoughtcrime.securesms.conversation.v2.messages
import android.content.Context import android.content.Context
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.text.StaticLayout
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.text.toSpannable 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.MentionUtilities
import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities
import org.thoughtcrime.securesms.database.SessionContactDatabase 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.GlideRequests
import org.thoughtcrime.securesms.mms.SlideDeck import org.thoughtcrime.securesms.mms.SlideDeck
import org.thoughtcrime.securesms.util.MediaUtil import org.thoughtcrime.securesms.util.MediaUtil
@ -26,7 +28,6 @@ import org.thoughtcrime.securesms.util.toPx
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.max import kotlin.math.max
import kotlin.math.min 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 // 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: // if you don't need to. If you do then test:
@ -61,10 +62,6 @@ class QuoteView : LinearLayout {
Mode.Regular -> { Mode.Regular -> {
binding.quoteViewCancelButton.isVisible = false binding.quoteViewCancelButton.isVisible = false
binding.mainQuoteViewContainer.setBackgroundColor(ResourcesCompat.getColor(resources, R.color.transparent, context.theme)) 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 we're showing an attachment thumbnail, just constrain to the height of that
if (binding.quoteViewAttachmentPreviewContainer.isVisible) { return toPx(40, resources) } if (binding.quoteViewAttachmentPreviewContainer.isVisible) { return toPx(40, resources) }
var result = 0 var result = 0
var authorTextViewIntrinsicHeight = 0 val authorTextViewIntrinsicHeight: Int
if (binding.quoteViewAuthorTextView.isVisible) { if (binding.quoteViewAuthorTextView.isVisible) {
val author = binding.quoteViewAuthorTextView.text val author = binding.quoteViewAuthorTextView.text
authorTextViewIntrinsicHeight = TextUtilities.getIntrinsicHeight(author, binding.quoteViewAuthorTextView.paint, maxContentWidth) authorTextViewIntrinsicHeight = TextUtilities.getIntrinsicHeight(author, binding.quoteViewAuthorTextView.paint, maxContentWidth)
@ -110,7 +107,7 @@ class QuoteView : LinearLayout {
// region Updating // region Updating
fun bind(authorPublicKey: String, body: String?, attachments: SlideDeck?, thread: Recipient, 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) { isOriginalMissing: Boolean, glide: GlideRequests) {
// Reduce the max body text view line count to 2 if this is a group thread because // 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 // 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 binding.quoteViewAuthorTextView.isVisible = thread.isGroupRecipient
// Body // 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)) binding.quoteViewBodyTextView.setTextColor(getTextColor(isOutgoingMessage))
// Accent line / attachment preview // Accent line / attachment preview
val hasAttachments = (attachments != null && attachments.asAttachments().isNotEmpty()) && !isOriginalMissing val hasAttachments = (attachments != null && attachments.asAttachments().isNotEmpty()) && !isOriginalMissing
binding.quoteViewAccentLine.isVisible = !hasAttachments binding.quoteViewAccentLine.isVisible = !hasAttachments
binding.quoteViewAttachmentPreviewContainer.isVisible = hasAttachments binding.quoteViewAttachmentPreviewContainer.isVisible = hasAttachments
if (!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)) binding.quoteViewAccentLine.setBackgroundColor(getLineColor(isOutgoingMessage))
} else if (attachments != null) { } else if (attachments != null) {
binding.quoteViewAttachmentPreviewImageView.imageTintList = ColorStateList.valueOf(ResourcesCompat.getColor(resources, R.color.white, context.theme)) 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 // endregion
@ -201,6 +190,31 @@ class QuoteView : LinearLayout {
ResourcesCompat.getColor(resources, R.color.white, context.theme) 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 // endregion
} }

View File

@ -5,6 +5,7 @@ import android.graphics.Color
import android.graphics.Rect import android.graphics.Rect
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.text.Spannable import android.text.Spannable
import android.text.StaticLayout
import android.text.style.BackgroundColorSpan import android.text.style.BackgroundColorSpan
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import android.text.style.URLSpan import android.text.style.URLSpan
@ -12,6 +13,7 @@ import android.text.util.Linkify
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.annotation.ColorInt 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.UiModeUtilities
import org.thoughtcrime.securesms.util.getColorWithID import org.thoughtcrime.securesms.util.getColorWithID
import org.thoughtcrime.securesms.util.toPx import org.thoughtcrime.securesms.util.toPx
import java.util.Locale import java.util.*
import kotlin.math.roundToInt import kotlin.math.roundToInt
class VisibleMessageContentView : LinearLayout { class VisibleMessageContentView : LinearLayout {
@ -89,9 +91,6 @@ class VisibleMessageContentView : LinearLayout {
} }
binding.quoteView.isVisible = message is MmsMessageRecord && message.quote != null 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() binding.linkPreviewView.isVisible = message is MmsMessageRecord && message.linkPreviews.isNotEmpty()
@ -120,7 +119,7 @@ class VisibleMessageContentView : LinearLayout {
quote.text quote.text
} }
binding.quoteView.bind(quote.author.toString(), quoteText, quote.attachment, thread, 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) quote.isOriginalMissing, glide)
onContentClick.add { event -> onContentClick.add { event ->
val r = Rect() 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 // set it to use constraints if not only a text message, otherwise wrap content to whatever width it wants
val params = binding.bodyTextView.layoutParams 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.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) { if (message.body.isNotEmpty() && !hideBody) {
val color = getTextColor(context, message) val color = getTextColor(context, message)
@ -209,6 +221,9 @@ class VisibleMessageContentView : LinearLayout {
} }
} }
private fun ViewVisibleMessageContentBinding.barrierViewsGone(): Boolean =
listOf<View>(albumThumbnailView, linkPreviewView, voiceMessageView, quoteView).none { it.isVisible }
private fun getBackground(isOutgoing: Boolean, isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean): Drawable { private fun getBackground(isOutgoing: Boolean, isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean): Drawable {
val isSingleMessage = (isStartOfMessageCluster && isEndOfMessageCluster) val isSingleMessage = (isStartOfMessageCluster && isEndOfMessageCluster)
@DrawableRes val backgroundID = when { @DrawableRes val backgroundID = when {

View File

@ -145,13 +145,13 @@ class VisibleMessageView : LinearLayout {
binding.messageTimestampTextView.text = DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), message.timestamp) binding.messageTimestampTextView.text = DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), message.timestamp)
// Margins // Margins
val startPadding = if (isGroupThread) { 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 { } else {
if (message.isOutgoing) resources.getDimension(R.dimen.very_large_spacing).toInt() if (message.isOutgoing) resources.getDimensionPixelSize(R.dimen.very_large_spacing)
else resources.getDimension(R.dimen.medium_spacing).toInt() else resources.getDimensionPixelSize(R.dimen.medium_spacing)
} }
val endPadding = if (message.isOutgoing) resources.getDimension(R.dimen.medium_spacing).toInt() val endPadding = if (message.isOutgoing) resources.getDimensionPixelSize(R.dimen.medium_spacing)
else resources.getDimension(R.dimen.very_large_spacing).toInt() else resources.getDimensionPixelSize(R.dimen.very_large_spacing)
binding.messageContentContainer.setPaddingRelative(startPadding, 0, endPadding, 0) binding.messageContentContainer.setPaddingRelative(startPadding, 0, endPadding, 0)
// Set inter-message spacing // Set inter-message spacing
setMessageSpacing(isStartOfMessageCluster, isEndOfMessageCluster) setMessageSpacing(isStartOfMessageCluster, isEndOfMessageCluster)

View File

@ -16,17 +16,17 @@
<org.thoughtcrime.securesms.conversation.v2.ConversationRecyclerView <org.thoughtcrime.securesms.conversation.v2.ConversationRecyclerView
android:id="@+id/conversationRecyclerView" android:id="@+id/conversationRecyclerView"
android:layout_above="@+id/typingIndicatorViewContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent" />
android:layout_marginBottom="@dimen/input_bar_height" />
<org.thoughtcrime.securesms.conversation.v2.components.TypingIndicatorViewContainer <org.thoughtcrime.securesms.conversation.v2.components.TypingIndicatorViewContainer
android:id="@+id/typingIndicatorViewContainer" android:id="@+id/typingIndicatorViewContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="36dp" android:layout_height="36dp"
android:layout_marginBottom="@dimen/input_bar_height"
android:visibility="gone" android:visibility="gone"
android:layout_alignParentBottom="true" /> android:layout_above="@+id/inputBar"
/>
<org.thoughtcrime.securesms.conversation.v2.input_bar.InputBar <org.thoughtcrime.securesms.conversation.v2.input_bar.InputBar
android:id="@+id/inputBar" android:id="@+id/inputBar"
@ -92,23 +92,23 @@
android:layout_width="40dp" android:layout_width="40dp"
android:layout_height="50dp" android:layout_height="50dp"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:layout_alignParentBottom="true" android:layout_above="@+id/inputBar"
android:layout_marginRight="12dp" android:layout_marginRight="12dp"
android:layout_marginBottom="72dp"> android:layout_marginBottom="32dp">
<RelativeLayout <RelativeLayout
android:layout_width="40dp" android:layout_width="40dp"
android:layout_height="40dp" android:layout_height="40dp"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/view_scroll_to_bottom_button_background"> android:background="@drawable/view_scroll_to_bottom_button_background">
<ImageView <ImageView
android:layout_width="16dp" android:layout_width="16dp"
android:layout_height="16dp" android:layout_height="16dp"
android:src="@drawable/ic_chevron_up"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:rotation="180" android:rotation="180"
android:src="@drawable/ic_chevron_up"
app:tint="@color/text" /> app:tint="@color/text" />
</RelativeLayout> </RelativeLayout>

View File

@ -3,7 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/inputBarLinearLayout" android:id="@+id/inputBarLinearLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/input_bar_height" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:background="@color/input_bar_background"> android:background="@color/input_bar_background">

View File

@ -1,29 +1,40 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/mainQuoteViewContainer" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mainQuoteViewContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/input_bar_background" android:background="@color/input_bar_background"
android:paddingHorizontal="@dimen/medium_spacing" android:paddingHorizontal="@dimen/medium_spacing"
xmlns:tools="http://schemas.android.com/tools"> android:paddingVertical="@dimen/small_spacing">
<View <View
android:id="@+id/quoteViewAccentLine" android:id="@+id/quoteViewAccentLine"
android:layout_width="@dimen/accent_line_thickness" android:layout_width="@dimen/accent_line_thickness"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:background="@color/text" /> 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" />
<RelativeLayout <RelativeLayout
tools:visibility="gone"
android:id="@+id/quoteViewAttachmentPreviewContainer" android:id="@+id/quoteViewAttachmentPreviewContainer"
android:layout_width="40dp" android:layout_width="40dp"
android:layout_height="40dp" android:layout_height="40dp"
android:layout_alignParentStart="true"
android:layout_marginVertical="@dimen/small_spacing"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:background="@drawable/view_quote_attachment_preview_background"> 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">
<ImageView <ImageView
android:id="@+id/quoteViewAttachmentPreviewImageView" android:id="@+id/quoteViewAttachmentPreviewImageView"
@ -42,50 +53,62 @@
</RelativeLayout> </RelativeLayout>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/quoteStartBarrier"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:barrierDirection="end"
app:constraint_referenced_ids="quoteViewAttachmentPreviewContainer,quoteViewAccentLine" />
<LinearLayout <LinearLayout
android:id="@+id/quoteViewMainContentContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginVertical="@dimen/small_spacing" android:layout_marginVertical="@dimen/small_spacing"
android:id="@+id/quoteTextParent"
android:layout_marginStart="@dimen/medium_spacing" android:layout_marginStart="@dimen/medium_spacing"
android:layout_marginEnd="@dimen/medium_spacing" android:layout_marginEnd="@dimen/medium_spacing"
android:layout_toEndOf="@+id/quoteViewAttachmentPreviewContainer" app:layout_constraintHorizontal_bias="0"
android:layout_toStartOf="@+id/quoteViewCancelButton" app:layout_constraintStart_toEndOf="@+id/quoteStartBarrier"
android:gravity="center_vertical" app:layout_constraintEnd_toStartOf="@id/quoteViewCancelButton"
android:orientation="vertical"> app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="wrap_content">
<TextView <TextView
tools:visibility="gone"
android:id="@+id/quoteViewAuthorTextView" android:id="@+id/quoteViewAuthorTextView"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
tools:text="Spiderman"
android:textColor="@color/text" android:textColor="@color/text"
android:textSize="@dimen/small_font_size" android:textSize="@dimen/small_font_size"
android:textStyle="bold" /> android:textStyle="bold"
tools:text="Spiderman" />
<TextView <TextView
android:id="@+id/quoteViewBodyTextView" android:id="@+id/quoteViewBodyTextView"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="3" android:maxLines="3"
tools:text="Yo, I need your help here!"
android:textColor="@color/text" android:textColor="@color/text"
android:textSize="@dimen/small_font_size" /> android:textSize="@dimen/small_font_size"
tools:text="@tools:sample/lorem/random" />
</LinearLayout> </LinearLayout>
<ImageView <ImageView
tools:visibility="gone"
android:id="@+id/quoteViewCancelButton" android:id="@+id/quoteViewCancelButton"
android:layout_width="32dp" android:layout_width="32dp"
android:layout_height="32dp" android:layout_height="32dp"
android:layout_marginStart="@dimen/small_spacing"
android:layout_marginEnd="@dimen/small_spacing"
android:padding="6dp" android:padding="6dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_close_white_48dp" android:src="@drawable/ic_close_white_48dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="@color/text" /> app:tint="@color/text" />
</RelativeLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -14,48 +14,35 @@
android:textStyle="bold" android:textStyle="bold"
android:gravity="center" /> android:gravity="center" />
<LinearLayout <RelativeLayout
android:id="@+id/mainContainer" android:id="@+id/mainContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="bottom"> android:gravity="bottom">
<LinearLayout <FrameLayout
android:layout_alignBottom="@+id/messageContentContainer"
android:id="@+id/profilePictureContainer" android:id="@+id/profilePictureContainer"
android:layout_width="wrap_content" android:layout_width="50dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal"> android:orientation="horizontal">
<View
android:layout_width="12dp"
android:layout_height="0dp" />
<RelativeLayout
android:layout_width="26dp"
android:layout_height="32dp" >
<org.thoughtcrime.securesms.components.ProfilePictureView <org.thoughtcrime.securesms.components.ProfilePictureView
android:id="@+id/profilePictureView" android:id="@+id/profilePictureView"
android:layout_width="@dimen/very_small_profile_picture_size" android:layout_width="@dimen/very_small_profile_picture_size"
android:layout_height="@dimen/very_small_profile_picture_size" android:layout_height="@dimen/very_small_profile_picture_size"
android:layout_marginTop="3dp" /> android:layout_gravity="center" />
<ImageView <ImageView
android:id="@+id/moderatorIconImageView" android:id="@+id/moderatorIconImageView"
android:layout_width="16dp" android:layout_width="16dp"
android:layout_height="16dp" android:layout_height="16dp"
android:layout_marginEnd="@dimen/small_spacing"
android:src="@drawable/ic_crown" android:src="@drawable/ic_crown"
android:layout_alignParentEnd="true" android:layout_gravity="bottom|end" />
android:layout_alignParentBottom="true" />
</RelativeLayout> </FrameLayout>
<View
android:layout_width="12dp"
android:layout_height="0dp" />
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/messageContentContainer" android:id="@+id/messageContentContainer"
@ -122,6 +109,6 @@
</LinearLayout> </LinearLayout>
</LinearLayout> </RelativeLayout>
</LinearLayout> </LinearLayout>

View File

@ -59,11 +59,10 @@
<org.thoughtcrime.securesms.conversation.v2.messages.QuoteView <org.thoughtcrime.securesms.conversation.v2.messages.QuoteView
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="@+id/albumThumbnailView" tools:visibility="visible"
app:layout_constraintHorizontal_bias="0"
android:visibility="gone" android:visibility="gone"
android:id="@+id/quoteView" android:id="@+id/quoteView"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<org.thoughtcrime.securesms.conversation.v2.messages.LinkPreviewView <org.thoughtcrime.securesms.conversation.v2.messages.LinkPreviewView
app:layout_constraintTop_toBottomOf="@+id/quoteView" app:layout_constraintTop_toBottomOf="@+id/quoteView"
@ -73,6 +72,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<androidx.constraintlayout.widget.Barrier <androidx.constraintlayout.widget.Barrier
app:barrierAllowsGoneWidgets="true"
android:id="@+id/bodyBarrier" android:id="@+id/bodyBarrier"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -125,5 +125,6 @@
<dimen name="drawable_padding">24dp</dimen> <dimen name="drawable_padding">24dp</dimen>
<dimen name="normal_padding">16dp</dimen> <dimen name="normal_padding">16dp</dimen>
<dimen name="action_item_height">56dp</dimen> <dimen name="action_item_height">56dp</dimen>
<dimen name="conversation_item_quote_width">120dp</dimen>
</resources> </resources>