diff --git a/vector/src/main/java/im/vector/app/core/ui/views/BubbleDependentView.kt b/vector/src/main/java/im/vector/app/core/ui/views/BubbleDependentView.kt new file mode 100644 index 0000000000..68c4243add --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/ui/views/BubbleDependentView.kt @@ -0,0 +1,55 @@ +package im.vector.app.core.ui.views + +import android.content.Context +import android.view.ViewGroup +import androidx.core.view.children +import im.vector.app.features.themes.BubbleThemeUtils + +interface BubbleDependentView { + + fun updateMessageBubble(context: Context, holder: H) { + val bubbleStyleSetting = BubbleThemeUtils.getBubbleStyle(context) + val bubbleStyle = when { + messageBubbleAllowed(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) + } + + fun messageBubbleAllowed(context: Context): Boolean { + return false + } + + fun shouldReverseBubble(): Boolean { + return false + } + + fun pseudoBubbleAllowed(): Boolean { + return false + } + + fun setBubbleLayout(holder: H, bubbleStyle: String, bubbleStyleSetting: String, reverseBubble: Boolean) + + 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 + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt index 041cec85e1..1e7a01c384 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt @@ -31,13 +31,14 @@ import im.vector.app.R import im.vector.app.core.epoxy.VectorEpoxyHolder import im.vector.app.core.epoxy.VectorEpoxyModel import im.vector.app.core.platform.CheckableView +import im.vector.app.core.ui.views.BubbleDependentView import im.vector.app.core.utils.DimensionConverter import im.vector.app.features.themes.BubbleThemeUtils /** * Children must override getViewType() */ -abstract class BaseEventItem : VectorEpoxyModel(), ItemWithEvents { +abstract class BaseEventItem : VectorEpoxyModel(), ItemWithEvents, BubbleDependentView { // To use for instance when opening a permalink with an eventId @EpoxyAttribute @@ -61,7 +62,7 @@ abstract class BaseEventItem : VectorEpoxyModel } holder.checkableBackground.isChecked = highlighted - updateMessageBubble(holder) + updateMessageBubble(holder.checkableBackground.context, holder) } abstract class BaseHolder(@IdRes val stubId: Int) : VectorEpoxyHolder() { @@ -82,52 +83,20 @@ abstract class BaseEventItem : VectorEpoxyModel 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 = 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) - } - - open fun messageBubbleAllowed(context: Context): Boolean { + override fun messageBubbleAllowed(context: Context): Boolean { return false } - open fun shouldReverseBubble(): Boolean { + override fun shouldReverseBubble(): Boolean { return false } - open fun pseudoBubbleAllowed(): Boolean { + override fun pseudoBubbleAllowed(): Boolean { return false } @CallSuper - open fun setBubbleLayout(holder: H, bubbleStyle: String, bubbleStyleSetting: String, reverseBubble: Boolean) { + override fun setBubbleLayout(holder: H, bubbleStyle: String, bubbleStyleSetting: String, reverseBubble: Boolean) { /* TODO-SC-merge: read receipt layout alignment val defaultDirection = holder.readReceiptsView.resources.configuration.layoutDirection; val defaultRtl = defaultDirection == View.LAYOUT_DIRECTION_RTL diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/ReadReceiptsItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/ReadReceiptsItem.kt index b88afb0598..99e7dfc537 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/ReadReceiptsItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/ReadReceiptsItem.kt @@ -16,17 +16,24 @@ package im.vector.app.features.home.room.detail.timeline.item +import android.view.Gravity import android.view.View +import android.widget.FrameLayout +import android.widget.LinearLayout +import android.widget.RelativeLayout import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelWithHolder import im.vector.app.R import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.ui.views.BubbleDependentView import im.vector.app.core.ui.views.ReadReceiptsView import im.vector.app.features.home.AvatarRenderer +import im.vector.app.features.themes.BubbleThemeUtils +import timber.log.Timber @EpoxyModelClass(layout = R.layout.item_timeline_event_read_receipts) -abstract class ReadReceiptsItem : EpoxyModelWithHolder(), ItemWithEvents { +abstract class ReadReceiptsItem : EpoxyModelWithHolder(), ItemWithEvents, BubbleDependentView { @EpoxyAttribute lateinit var eventId: String @EpoxyAttribute lateinit var readReceipts: List @@ -40,6 +47,8 @@ abstract class ReadReceiptsItem : EpoxyModelWithHolder( override fun bind(holder: Holder) { super.bind(holder) holder.readReceiptsView.render(readReceipts, avatarRenderer, clickListener) + + updateMessageBubble(holder.readReceiptsView.context, holder) } override fun unbind(holder: Holder) { @@ -50,4 +59,47 @@ abstract class ReadReceiptsItem : EpoxyModelWithHolder( class Holder : VectorEpoxyHolder() { val readReceiptsView by bind(R.id.readReceiptsView) } + + override fun setBubbleLayout(holder: Holder, 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 = BubbleThemeUtils.drawsDualSide(bubbleStyleSetting) + + /* + 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 (receiptParent is RelativeLayout) { + 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) + } + } else if (receiptParent is FrameLayout) { + */ + if (dualBubbles) { + (holder.readReceiptsView.layoutParams as FrameLayout.LayoutParams).gravity = Gravity.START + } else { + (holder.readReceiptsView.layoutParams as FrameLayout.LayoutParams).gravity = Gravity.END + } + /* + } else { + Timber.e("Unsupported layout for read receipts parent: $receiptParent") + } + */ + + // Also set rtl to have members fill from the natural side + setFlatRtl(holder.readReceiptsView, if (dualBubbles) reverseDirection else defaultDirection, defaultDirection) + } }