Same side read receipts for both side bubbles

This commit is contained in:
SpiritCroc 2020-05-28 12:56:28 +02:00
parent 37a64004e4
commit 043a908d24
4 changed files with 101 additions and 31 deletions

View File

@ -32,6 +32,7 @@ import androidx.annotation.IdRes
import androidx.core.view.children import androidx.core.view.children
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.ui.views.ReadReceiptsView
import im.vector.riotx.core.utils.DebouncedClickListener import im.vector.riotx.core.utils.DebouncedClickListener
import im.vector.riotx.features.home.AvatarRenderer import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.home.room.detail.timeline.MessageColorProvider import im.vector.riotx.features.home.room.detail.timeline.MessageColorProvider
@ -116,7 +117,6 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
} }
} }
holder.viewStubContainer.minimumWidth = getViewStubMinimumWidth(holder, contentInBubble, attributes.informationData.showInformation) holder.viewStubContainer.minimumWidth = getViewStubMinimumWidth(holder, contentInBubble, attributes.informationData.showInformation)
updateMessageBubble(holder)
} }
abstract class Holder(@IdRes stubId: Int) : AbsBaseMessageItem.Holder(stubId) { abstract class Holder(@IdRes stubId: Int) : AbsBaseMessageItem.Holder(stubId) {
@ -127,7 +127,6 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
val bubbleView by bind<View>(R.id.bubbleView) val bubbleView by bind<View>(R.id.bubbleView)
val bubbleMemberNameView by bind<TextView>(R.id.bubbleMessageMemberNameView) val bubbleMemberNameView by bind<TextView>(R.id.bubbleMessageMemberNameView)
val bubbleTimeView by bind<TextView>(R.id.bubbleMessageTimeView) val bubbleTimeView by bind<TextView>(R.id.bubbleMessageTimeView)
val informationBottom by bind<LinearLayout>(R.id.informationBottom)
val viewStubContainer by bind<FrameLayout>(R.id.viewStubContainer) val viewStubContainer by bind<FrameLayout>(R.id.viewStubContainer)
} }
@ -152,10 +151,6 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
return infoInBubbles(context) && attributes.informationData.sentByMe return infoInBubbles(context) && attributes.informationData.sentByMe
} }
open fun messageBubbleAllowed(context: Context): Boolean {
return false
}
open fun getViewStubMinimumWidth(holder: H, contentInBubble: Boolean, showInformation: Boolean): Int { open fun getViewStubMinimumWidth(holder: H, contentInBubble: Boolean, showInformation: Boolean): Int {
return if (contentInBubble && attributes.informationData.showInformation) { return if (contentInBubble && attributes.informationData.showInformation) {
// Guess text width for name and time // Guess text width for name and time
@ -168,13 +163,16 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
} }
} }
fun infoInBubbles(context: Context): Boolean { private fun infoInBubbles(context: Context): Boolean {
return messageBubbleAllowed(context) && BubbleThemeUtils.getBubbleStyle(context) == BubbleThemeUtils.BUBBLE_STYLE_BOTH return messageBubbleAllowed(context) && BubbleThemeUtils.getBubbleStyle(context) == BubbleThemeUtils.BUBBLE_STYLE_BOTH
} }
fun updateMessageBubble(holder: H) { override fun shouldReverseBubble(): Boolean {
val bubbleStyle = if (messageBubbleAllowed(holder.eventBaseView.context)) BubbleThemeUtils.getBubbleStyle(holder.eventBaseView.context) else BubbleThemeUtils.BUBBLE_STYLE_NONE return attributes.informationData.sentByMe
val reverseBubble = attributes.informationData.sentByMe && bubbleStyle == BubbleThemeUtils.BUBBLE_STYLE_BOTH }
override fun setBubbleLayout(holder: H, bubbleStyle: String, bubbleStyleSetting: String, reverseBubble: Boolean) {
super.setBubbleLayout(holder, bubbleStyle, bubbleStyleSetting, reverseBubble)
//val bubbleView = holder.eventBaseView //val bubbleView = holder.eventBaseView
val bubbleView = holder.bubbleView val bubbleView = holder.bubbleView
@ -232,32 +230,16 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
} }
} }
val defaultRtl = holder.eventBaseView.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL; val defaultDirection = holder.eventBaseView.resources.configuration.layoutDirection;
val shouldRtl = reverseBubble != defaultRtl val defaultRtl = defaultDirection == View.LAYOUT_DIRECTION_RTL
val reverseDirection = if (defaultRtl) View.LAYOUT_DIRECTION_LTR else View.LAYOUT_DIRECTION_RTL
/* /*
holder.eventBaseView.layoutDirection = if (shouldRtl) View.LAYOUT_DIRECTION_RTL else View.LAYOUT_DIRECTION_LTR holder.eventBaseView.layoutDirection = if (shouldRtl) View.LAYOUT_DIRECTION_RTL else View.LAYOUT_DIRECTION_LTR
setRtl(shouldRtl) setRtl(shouldRtl)
*/ */
(holder.bubbleView.layoutParams as FrameLayout.LayoutParams).gravity = if (reverseBubble) Gravity.END else Gravity.START (holder.bubbleView.layoutParams as FrameLayout.LayoutParams).gravity = if (reverseBubble) Gravity.END else Gravity.START
//holder.informationBottom.layoutDirection = if (shouldRtl) View.LAYOUT_DIRECTION_RTL else View.LAYOUT_DIRECTION_LTR //holder.informationBottom.layoutDirection = if (shouldRtl) View.LAYOUT_DIRECTION_RTL else View.LAYOUT_DIRECTION_LTR
setFlatRtl(holder.informationBottom, if (shouldRtl) View.LAYOUT_DIRECTION_RTL else View.LAYOUT_DIRECTION_LTR, setFlatRtl(holder.reactionsContainer, if (reverseBubble) reverseDirection else defaultDirection,
holder.eventBaseView.resources.configuration.layoutDirection, 2) holder.eventBaseView.resources.configuration.layoutDirection)
}
/*
open fun setRtl(rtl: Boolean) {
// TODO subclass overrides?
}
*/
fun setFlatRtl(layout: ViewGroup, direction: Int, childDirection: Int, depth: Int = 1) {
layout.layoutDirection = direction
for (child in layout.children) {
if (depth > 1 && child is ViewGroup) {
setFlatRtl(child, direction, childDirection, depth-1)
} else {
child.layoutDirection = childDirection
}
}
} }
} }

View File

@ -16,11 +16,15 @@
package im.vector.riotx.features.home.room.detail.timeline.item package im.vector.riotx.features.home.room.detail.timeline.item
import android.content.Context import android.content.Context
import android.view.Gravity
import android.view.View import android.view.View
import android.view.ViewGroup
import android.view.ViewStub import android.view.ViewStub
import android.widget.LinearLayout
import android.widget.RelativeLayout import android.widget.RelativeLayout
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import androidx.annotation.IdRes import androidx.annotation.IdRes
import androidx.core.view.children
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import im.vector.riotx.R import im.vector.riotx.R
@ -29,6 +33,7 @@ import im.vector.riotx.core.epoxy.VectorEpoxyModel
import im.vector.riotx.core.platform.CheckableView import im.vector.riotx.core.platform.CheckableView
import im.vector.riotx.core.ui.views.ReadReceiptsView import im.vector.riotx.core.ui.views.ReadReceiptsView
import im.vector.riotx.core.utils.DimensionConverter import im.vector.riotx.core.utils.DimensionConverter
import im.vector.riotx.features.themes.BubbleThemeUtils
/** /**
* Children must override getViewType() * Children must override getViewType()
@ -55,6 +60,8 @@ abstract class BaseEventItem<H : BaseEventItem.BaseHolder> : VectorEpoxyModel<H>
} }
} }
holder.checkableBackground.isChecked = highlighted holder.checkableBackground.isChecked = highlighted
updateMessageBubble(holder)
} }
/** /**
@ -81,4 +88,64 @@ abstract class BaseEventItem<H : BaseEventItem.BaseHolder> : VectorEpoxyModel<H>
open fun ignoreMessageGuideline(context: Context): Boolean { open fun ignoreMessageGuideline(context: Context): Boolean {
return false return false
} }
protected fun setFlatRtl(layout: ViewGroup, direction: Int, childDirection: Int, depth: Int = 1) {
layout.layoutDirection = direction
for (child in layout.children) {
if (depth > 1 && child is ViewGroup) {
setFlatRtl(child, direction, childDirection, depth-1)
} else {
child.layoutDirection = childDirection
}
}
}
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
setBubbleLayout(holder, bubbleStyle, bubbleStyleSetting, reverseBubble)
}
open fun messageBubbleAllowed(context: Context): Boolean {
return false
}
open fun shouldReverseBubble(): Boolean {
return false
}
@CallSuper
open fun setBubbleLayout(holder: H, bubbleStyle: String, bubbleStyleSetting: String, reverseBubble: Boolean) {
val defaultDirection = holder.readReceiptsView.resources.configuration.layoutDirection;
val defaultRtl = defaultDirection == View.LAYOUT_DIRECTION_RTL
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 receiptParent = holder.readReceiptsView.parent
if (receiptParent is LinearLayout) {
(holder.readReceiptsView.layoutParams as LinearLayout.LayoutParams).gravity = if (dualBubbles) Gravity.START else Gravity.END
(receiptParent.layoutParams as RelativeLayout.LayoutParams).removeRule(RelativeLayout.END_OF)
(receiptParent.layoutParams as RelativeLayout.LayoutParams).removeRule(RelativeLayout.ALIGN_PARENT_START)
if (dualBubbles) {
(receiptParent.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.ALIGN_PARENT_START, RelativeLayout.TRUE)
} else {
(receiptParent.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.END_OF, R.id.messageStartGuideline)
}
} else {
if (dualBubbles) {
(holder.readReceiptsView.layoutParams as RelativeLayout.LayoutParams).removeRule(RelativeLayout.ALIGN_PARENT_END)
} else {
(holder.readReceiptsView.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.ALIGN_PARENT_END)
}
}
// Also set rtl to have members fill from the natural side
setFlatRtl(holder.readReceiptsView, if (dualBubbles) reverseDirection else defaultDirection, defaultDirection)
}
} }

View File

@ -235,6 +235,17 @@
</com.google.android.flexbox.FlexboxLayout> </com.google.android.flexbox.FlexboxLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/informationBottom2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/informationBottom"
android:layout_toEndOf="@id/messageStartGuideline"
android:orientation="vertical">
<im.vector.riotx.core.ui.views.ReadReceiptsView <im.vector.riotx.core.ui.views.ReadReceiptsView
android:id="@+id/readReceiptsView" android:id="@+id/readReceiptsView"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@ -105,6 +105,16 @@
</com.google.android.flexbox.FlexboxLayout> </com.google.android.flexbox.FlexboxLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/informationBottom2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/informationBottom"
android:layout_toEndOf="@id/messageStartGuideline"
android:orientation="vertical">
<im.vector.riotx.core.ui.views.ReadReceiptsView <im.vector.riotx.core.ui.views.ReadReceiptsView
android:id="@+id/readReceiptsView" android:id="@+id/readReceiptsView"
android:layout_width="wrap_content" android:layout_width="wrap_content"