diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt index 490272d8e4..ab6c11dcb5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt @@ -1,11 +1,14 @@ package org.thoughtcrime.securesms.conversation.v2.messages import android.content.Context +import android.content.res.Resources import android.util.AttributeSet +import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout import androidx.core.content.res.ResourcesCompat +import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.view_control_message.view.* import network.loki.messenger.R import org.thoughtcrime.securesms.database.model.MessageRecord @@ -19,6 +22,7 @@ class ControlMessageView : LinearLayout { private fun initialize() { LayoutInflater.from(context).inflate(R.layout.view_control_message, this) + layoutParams = RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT) } // endregion 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 19943c70be..00a98d1d33 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 @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.conversation.v2.messages import android.content.Context +import android.graphics.Canvas import android.graphics.drawable.Drawable import android.util.AttributeSet import android.view.LayoutInflater @@ -9,12 +10,15 @@ import android.widget.LinearLayout import androidx.core.content.res.ResourcesCompat import kotlinx.android.synthetic.main.view_link_preview.view.* import network.loki.messenger.R +import org.thoughtcrime.securesms.components.CornerMask +import org.thoughtcrime.securesms.conversation.v2.utilities.MessageBubbleUtilities import org.thoughtcrime.securesms.database.model.MmsMessageRecord import org.thoughtcrime.securesms.loki.utilities.UiModeUtilities import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.mms.ImageSlide class LinkPreviewView : LinearLayout { + private val cornerMask by lazy { CornerMask(this) } // region Lifecycle constructor(context: Context) : super(context) { initialize() } @@ -27,7 +31,7 @@ class LinkPreviewView : LinearLayout { // endregion // region Updating - fun bind(message: MmsMessageRecord, glide: GlideRequests, background: Drawable) { + fun bind(message: MmsMessageRecord, glide: GlideRequests, isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean) { mainLinkPreviewContainer.background = background mainLinkPreviewContainer.outlineProvider = ViewOutlineProvider.BACKGROUND mainLinkPreviewContainer.clipToOutline = true @@ -48,6 +52,17 @@ class LinkPreviewView : LinearLayout { // Body val bodyTextView = VisibleMessageContentView.getBodyTextView(context, message) mainLinkPreviewContainer.addView(bodyTextView) + // Corner radii + val cornerRadii = MessageBubbleUtilities.calculateRadii(context, isStartOfMessageCluster, isEndOfMessageCluster, message.isOutgoing) + cornerMask.setTopLeftRadius(cornerRadii[0]) + cornerMask.setTopRightRadius(cornerRadii[1]) + cornerMask.setBottomRightRadius(cornerRadii[2]) + cornerMask.setBottomLeftRadius(cornerRadii[3]) + } + + override fun dispatchDraw(canvas: Canvas) { + super.dispatchDraw(canvas) + cornerMask.mask(canvas) } fun recycle() { 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 a0ea58f6e1..da12568ed4 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 @@ -59,7 +59,7 @@ class VisibleMessageContentView : LinearLayout { onContentClick = null if (message is MmsMessageRecord && message.linkPreviews.isNotEmpty()) { val linkPreviewView = LinkPreviewView(context) - linkPreviewView.bind(message, glide, background) + linkPreviewView.bind(message, glide, isStartOfMessageCluster, isEndOfMessageCluster) mainContainer.addView(linkPreviewView) // Body text view is inside the link preview for layout convenience } else if (message is MmsMessageRecord && message.quote != null) { @@ -77,7 +77,7 @@ class VisibleMessageContentView : LinearLayout { mainContainer.addView(bodyTextView) } else if (message is MmsMessageRecord && message.slideDeck.audioSlide != null) { val voiceMessageView = VoiceMessageView(context) - voiceMessageView.bind(message, background) + voiceMessageView.bind(message, isStartOfMessageCluster, isEndOfMessageCluster) mainContainer.addView(voiceMessageView) // We have to use onContentClick (rather than a click listener directly on the voice // message view) so as to not interfere with all the other gestures. diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt index f85ebec0f6..111f251805 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.conversation.v2.messages import android.content.Context +import android.graphics.Canvas import android.graphics.drawable.Drawable import android.os.Handler import android.os.Looper @@ -12,12 +13,15 @@ import android.widget.RelativeLayout import androidx.core.view.isVisible import kotlinx.android.synthetic.main.view_voice_message.view.* import network.loki.messenger.R +import org.thoughtcrime.securesms.components.CornerMask +import org.thoughtcrime.securesms.conversation.v2.utilities.MessageBubbleUtilities import org.thoughtcrime.securesms.database.model.MmsMessageRecord import java.util.concurrent.TimeUnit import kotlin.math.roundToInt class VoiceMessageView : LinearLayout { private val snHandler = Handler(Looper.getMainLooper()) + private val cornerMask by lazy { CornerMask(this) } private var runnable: Runnable? = null private var mockIsPlaying = false private var mockProgress = 0L @@ -38,12 +42,14 @@ class VoiceMessageView : LinearLayout { // endregion // region Updating - fun bind(message: MmsMessageRecord, background: Drawable) { + fun bind(message: MmsMessageRecord, isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean) { val audio = message.slideDeck.audioSlide!! voiceMessageViewLoader.isVisible = audio.isPendingDownload - mainVoiceMessageViewContainer.background = background - mainVoiceMessageViewContainer.outlineProvider = ViewOutlineProvider.BACKGROUND - mainVoiceMessageViewContainer.clipToOutline = true + val cornerRadii = MessageBubbleUtilities.calculateRadii(context, isStartOfMessageCluster, isEndOfMessageCluster, message.isOutgoing) + cornerMask.setTopLeftRadius(cornerRadii[0]) + cornerMask.setTopRightRadius(cornerRadii[1]) + cornerMask.setBottomRightRadius(cornerRadii[2]) + cornerMask.setBottomLeftRadius(cornerRadii[3]) } private fun handleProgressChanged() { @@ -56,6 +62,11 @@ class VoiceMessageView : LinearLayout { progressView.layoutParams = layoutParams } + override fun dispatchDraw(canvas: Canvas) { + super.dispatchDraw(canvas) + cornerMask.mask(canvas) + } + fun recycle() { // TODO: Implement } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/MessageBubbleUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/MessageBubbleUtilities.kt new file mode 100644 index 0000000000..c4c5d5a5d8 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/MessageBubbleUtilities.kt @@ -0,0 +1,31 @@ +package org.thoughtcrime.securesms.conversation.v2.utilities + +import android.content.Context +import network.loki.messenger.R +import kotlin.math.roundToInt + +object MessageBubbleUtilities { + + fun calculateRadii(context: Context, isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean, isOutgoing: Boolean): IntArray { + val roundedDimen = context.resources.getDimension(R.dimen.message_corner_radius).roundToInt() + val collapsedDimen = context.resources.getDimension(R.dimen.message_corner_collapse_radius).roundToInt() + val (tl, tr, bl, br) = when { + // Single message + isStartOfMessageCluster && isEndOfMessageCluster -> intArrayOf(roundedDimen, roundedDimen, roundedDimen, roundedDimen) + // Start of message cluster; collapsed BL + isStartOfMessageCluster -> intArrayOf(roundedDimen, roundedDimen, collapsedDimen, roundedDimen) + // End of message cluster; collapsed TL + isEndOfMessageCluster -> intArrayOf(collapsedDimen, roundedDimen, roundedDimen, roundedDimen) + // In the middle; no rounding on the left + else -> intArrayOf(collapsedDimen, roundedDimen, collapsedDimen, roundedDimen) + } + // TL, TR, BR, BL (CW direction) + // Flip if the message is outgoing + return intArrayOf( + if (!isOutgoing) tl else tr, // TL + if (!isOutgoing) tr else tl, // TR + if (!isOutgoing) br else bl, // BR + if (!isOutgoing) bl else br // BL + ) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/view_control_message.xml b/app/src/main/res/layout/view_control_message.xml index 714c7150ee..5dbbe14ab6 100644 --- a/app/src/main/res/layout/view_control_message.xml +++ b/app/src/main/res/layout/view_control_message.xml @@ -16,7 +16,7 @@