Use pseudo-bubbles for for ImageVideo items

Pseudo-bubbles: align like bubbles, but don't draw the actual bubbles.
Closes #8.

Change-Id: I8ff281858f67ed8a3ee5e4530e3ce02aa786b955
This commit is contained in:
SpiritCroc 2020-09-25 12:40:54 +02:00
parent 0d7c0bc29c
commit 037a333c37
4 changed files with 88 additions and 27 deletions

View file

@ -25,11 +25,9 @@ import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.annotation.IdRes
import androidx.core.view.children
import com.airbnb.epoxy.EpoxyAttribute
import kotlin.math.max
import kotlin.math.round
@ -84,7 +82,17 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
holder.avatarImageView.setOnLongClickListener(attributes.itemLongClickListener)
holder.memberNameView.setOnLongClickListener(attributes.itemLongClickListener)
holder.bubbleMemberNameView.setOnLongClickListener(attributes.itemLongClickListener)
if (contentInBubble) {
if (hideSenderInformation()) {
holder.memberNameView.visibility = View.GONE
holder.timeView.visibility = View.GONE
holder.bubbleMemberNameView.visibility = View.GONE
holder.bubbleTimeView.visibility = View.GONE
if (attributes.informationData.isDirect) {
holder.avatarImageView.visibility = View.GONE
} else {
holder.avatarImageView.visibility = View.VISIBLE
}
} else if (contentInBubble) {
holder.memberNameView.visibility = View.GONE
holder.timeView.visibility = View.GONE
holder.bubbleMemberNameView.visibility = View.VISIBLE
@ -109,7 +117,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
holder.timeView.visibility = View.GONE
holder.avatarImageView.setOnLongClickListener(null)
holder.memberNameView.setOnLongClickListener(null)
if (attributes.informationData.showInformation /* && contentInBubble && attributes.informationData.sentByMe */) {
if (attributes.informationData.showInformation && !hideSenderInformation()/* && contentInBubble && attributes.informationData.sentByMe */) {
holder.bubbleTimeView.visibility = View.VISIBLE
holder.bubbleTimeView.text = attributes.informationData.time
holder.bubbleMemberNameView.visibility = View.VISIBLE
@ -203,13 +211,18 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
}
private fun infoInBubbles(context: Context): Boolean {
return messageBubbleAllowed(context) && BubbleThemeUtils.getBubbleStyle(context) == BubbleThemeUtils.BUBBLE_STYLE_BOTH
return BubbleThemeUtils.getBubbleStyle(context) == BubbleThemeUtils.BUBBLE_STYLE_BOTH &&
(messageBubbleAllowed(context) || pseudoBubbleAllowed())
}
override fun shouldReverseBubble(): Boolean {
return attributes.informationData.sentByMe
}
private fun hideSenderInformation(): Boolean {
return pseudoBubbleAllowed() && false
}
open fun getBubbleMargin(density: Float, reverseBubble: Boolean): Int {
return round(96*density).toInt()
}
@ -231,7 +244,13 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
*/
bubbleView.setPadding(0, 0, 0, 0)
}
BubbleThemeUtils.BUBBLE_STYLE_START, BubbleThemeUtils.BUBBLE_STYLE_BOTH -> {
BubbleThemeUtils.BUBBLE_STYLE_START,
BubbleThemeUtils.BUBBLE_STYLE_BOTH,
BubbleThemeUtils.BUBBLE_STYLE_BOTH_HIDDEN,
BubbleThemeUtils.BUBBLE_STYLE_START_HIDDEN -> {
val longPadding: Int
val shortPadding: Int
if (BubbleThemeUtils.drawsActualBubbles(bubbleStyle)) {
if (attributes.informationData.showInformation) {
bubbleView.setBackgroundResource(if (reverseBubble) R.drawable.msg_bubble_outgoing else R.drawable.msg_bubble_incoming)
} else {
@ -244,6 +263,12 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
)
)
bubbleView.backgroundTintList = tintColor
longPadding = 20
shortPadding = 8
} else {
longPadding = 10
shortPadding = 0//if (attributes.informationData.showInformation && !hideSenderInformation()) { 8 } else { 0 }
}
val density = bubbleView.resources.displayMetrics.density
// TODO 96 = 2 * avatar size?
if (reverseBubble) {
@ -261,17 +286,17 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
// TODO padding?
if (reverseBubble) {
bubbleView.setPaddingRelative(
round(8 * density).toInt(),
round(8 * density).toInt(),
round(20 * density).toInt(),
round(8 * density).toInt()
round(shortPadding * density).toInt(),
round(shortPadding * density).toInt(),
round(longPadding * density).toInt(),
round(shortPadding * density).toInt()
)
} else {
bubbleView.setPaddingRelative(
round(20 * density).toInt(),
round(8 * density).toInt(),
round(8 * density).toInt(),
round(8 * density).toInt()
round(longPadding * density).toInt(),
round(shortPadding * density).toInt(),
round(shortPadding * density).toInt(),
round(shortPadding * density).toInt()
)
}
}

View file

@ -102,8 +102,21 @@ abstract class BaseEventItem<H : BaseEventItem.BaseHolder> : VectorEpoxyModel<H>
fun updateMessageBubble(holder: H) {
val bubbleStyleSetting = BubbleThemeUtils.getBubbleStyle(holder.checkableBackground.context)
val bubbleStyle = if (messageBubbleAllowed(holder.checkableBackground.context)) bubbleStyleSetting else BubbleThemeUtils.BUBBLE_STYLE_NONE
val reverseBubble = shouldReverseBubble() && bubbleStyle == BubbleThemeUtils.BUBBLE_STYLE_BOTH
val bubbleStyle = when {
messageBubbleAllowed(holder.checkableBackground.context) -> {
bubbleStyleSetting
}
bubbleStyleSetting == BubbleThemeUtils.BUBBLE_STYLE_BOTH && pseudoBubbleAllowed() -> {
BubbleThemeUtils.BUBBLE_STYLE_BOTH_HIDDEN
}
bubbleStyleSetting == BubbleThemeUtils.BUBBLE_STYLE_START && pseudoBubbleAllowed() -> {
BubbleThemeUtils.BUBBLE_STYLE_START_HIDDEN
}
else -> {
BubbleThemeUtils.BUBBLE_STYLE_NONE
}
}
val reverseBubble = shouldReverseBubble() && BubbleThemeUtils.drawsDualSide(bubbleStyle)
setBubbleLayout(holder, bubbleStyle, bubbleStyleSetting, reverseBubble)
}
@ -116,6 +129,10 @@ abstract class BaseEventItem<H : BaseEventItem.BaseHolder> : VectorEpoxyModel<H>
return false
}
open fun pseudoBubbleAllowed(): Boolean {
return false
}
@CallSuper
open fun setBubbleLayout(holder: H, bubbleStyle: String, bubbleStyleSetting: String, reverseBubble: Boolean) {
val defaultDirection = holder.readReceiptsView.resources.configuration.layoutDirection;
@ -123,7 +140,7 @@ abstract class BaseEventItem<H : BaseEventItem.BaseHolder> : VectorEpoxyModel<H>
val reverseDirection = if (defaultRtl) View.LAYOUT_DIRECTION_LTR else View.LAYOUT_DIRECTION_RTL
// Always keep read receipts of others on other side for dual side bubbles
val dualBubbles = bubbleStyleSetting == BubbleThemeUtils.BUBBLE_STYLE_BOTH
val dualBubbles = BubbleThemeUtils.drawsDualSide(bubbleStyleSetting)
val receiptParent = holder.readReceiptsView.parent
if (receiptParent is LinearLayout) {

View file

@ -84,6 +84,10 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
override fun getViewType() = STUB_ID
override fun messageBubbleAllowed(context: Context): Boolean {
return false
}
override fun pseudoBubbleAllowed(): Boolean {
return true
}

View file

@ -12,6 +12,13 @@ object BubbleThemeUtils {
const val BUBBLE_STYLE_NONE = "none"
const val BUBBLE_STYLE_START = "start"
const val BUBBLE_STYLE_BOTH = "both"
// Special case of BUBBLE_STYLE_BOTH, to allow non-bubble items align to the sender either way
// (not meant for user setting, but internal use)
const val BUBBLE_STYLE_BOTH_HIDDEN = "both_hidden"
// As above, so for single bubbles side
const val BUBBLE_STYLE_START_HIDDEN = "start_hidden"
private var mBubbleStyle: String = ""
fun getBubbleStyle(context: Context): String {
@ -21,6 +28,14 @@ object BubbleThemeUtils {
return mBubbleStyle
}
fun drawsActualBubbles(bubbleStyle: String): Boolean {
return bubbleStyle == BUBBLE_STYLE_START || bubbleStyle == BUBBLE_STYLE_BOTH
}
fun drawsDualSide(bubbleStyle: String): Boolean {
return bubbleStyle == BUBBLE_STYLE_BOTH || bubbleStyle == BUBBLE_STYLE_BOTH_HIDDEN
}
fun invalidateBubbleStyle() {
mBubbleStyle = ""
}