Bubbles: continue exploration

This commit is contained in:
ganfra 2022-01-11 11:57:35 +01:00
parent ad63d3de1c
commit f7c9b36cef
8 changed files with 20 additions and 19 deletions

View file

@ -3,7 +3,7 @@
<declare-styleable name="MessageBubble">
<attr name="incoming_style" format="boolean" />
<attr name="show_background" format="boolean" />
<attr name="show_time_overlay" format="boolean" />
<attr name="is_first" format="boolean" />
<attr name="is_last" format="boolean" />
</declare-styleable>

View file

@ -358,6 +358,9 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
// Should be build if not cached or if model should be refreshed
if (modelCache[position] == null || modelCache[position]?.isCacheable(partialState) == false) {
val prevEvent = currentSnapshot.prevOrNull(position)
val prevDisplayableEvent = currentSnapshot.subList(0, position).lastOrNull {
timelineEventVisibilityHelper.shouldShowEvent(it, partialState.highlightedEventId)
}
val nextDisplayableEvent = currentSnapshot.subList(position + 1, currentSnapshot.size).firstOrNull {
timelineEventVisibilityHelper.shouldShowEvent(it, partialState.highlightedEventId)
}
@ -365,6 +368,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
val params = TimelineItemFactoryParams(
event = event,
prevEvent = prevEvent,
prevDisplayableEvent = prevDisplayableEvent,
nextEvent = nextEvent,
nextDisplayableEvent = nextDisplayableEvent,
partialState = partialState,

View file

@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
data class TimelineItemFactoryParams(
val event: TimelineEvent,
val prevEvent: TimelineEvent? = null,
val prevDisplayableEvent: TimelineEvent? = null,
val nextEvent: TimelineEvent? = null,
val nextDisplayableEvent: TimelineEvent? = null,
val partialState: TimelineEventController.PartialState = TimelineEventController.PartialState(),

View file

@ -57,19 +57,21 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
fun create(params: TimelineItemFactoryParams): MessageInformationData {
val event = params.event
val nextDisplayableEvent = params.nextDisplayableEvent
val prevEvent = params.prevEvent
val prevDisplayableEvent = params.prevDisplayableEvent
val eventId = event.eventId
val isSentByMe = event.root.senderId == session.myUserId
val isFirstFromThisSender = nextDisplayableEvent?.root?.senderId != event.root.senderId
val isLastFromThisSender = prevEvent?.root?.senderId != event.root.senderId
val roomSummary = params.partialState.roomSummary
val date = event.root.localDateTime()
val nextDate = nextDisplayableEvent?.root?.localDateTime()
val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate()
val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60))
?: false
val isFirstFromThisSender = nextDisplayableEvent?.root?.senderId != event.root.senderId || addDaySeparator
val isLastFromThisSender = prevDisplayableEvent?.root?.senderId != event.root.senderId || prevDisplayableEvent?.root?.localDateTime()?.toLocalDate() != date.toLocalDate()
val showInformation =
(addDaySeparator ||
event.senderInfo.avatarUrl != nextDisplayableEvent?.senderInfo?.avatarUrl ||
@ -77,7 +79,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
nextDisplayableEvent.root.getClearType() !in listOf(EventType.MESSAGE, EventType.STICKER, EventType.ENCRYPTED) ||
isNextMessageReceivedMoreThanOneHourAgo ||
isTileTypeMessage(nextDisplayableEvent) ||
nextDisplayableEvent.isEdition() ) && !isSentByMe
nextDisplayableEvent.isEdition()) && !isSentByMe
val time = dateFormatter.format(event.root.originServerTs, DateFormatKind.MESSAGE_SIMPLE)
val e2eDecoration = getE2EDecoration(roomSummary, event)

View file

@ -29,7 +29,6 @@ import im.vector.app.core.epoxy.onClick
import im.vector.app.core.files.LocalFilesHelper
import im.vector.app.core.glide.GlideApp
import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
import im.vector.app.features.home.room.detail.timeline.view.MessageBubbleView
import im.vector.app.features.home.room.detail.timeline.view.MessageViewConfiguration
import im.vector.app.features.media.ImageContentRenderer
@ -72,7 +71,7 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
holder.mediaContentView.onClick(attributes.itemClickListener)
holder.mediaContentView.setOnLongClickListener(attributes.itemLongClickListener)
holder.playContentView.visibility = if (playable) View.VISIBLE else View.GONE
(holder.view as? MessageViewConfiguration)?.displayBorder = false
(holder.view as? MessageViewConfiguration)?.showTimeAsOverlay = false
}
override fun unbind(holder: Holder) {

View file

@ -54,7 +54,7 @@ class MessageBubbleView @JvmOverloads constructor(context: Context, attrs: Attri
render()
}
override var displayBorder: Boolean = true
override var showTimeAsOverlay: Boolean = true
set(value) {
field = value
render()
@ -66,7 +66,7 @@ class MessageBubbleView @JvmOverloads constructor(context: Context, attrs: Attri
inflate(context, R.layout.view_message_bubble, this)
context.withStyledAttributes(attrs, R.styleable.MessageBubble) {
isIncoming = getBoolean(R.styleable.MessageBubble_incoming_style, false)
displayBorder = getBoolean(R.styleable.MessageBubble_show_background, true)
showTimeAsOverlay = getBoolean(R.styleable.MessageBubble_show_time_overlay, true)
isFirstFromSender = getBoolean(R.styleable.MessageBubble_is_first, false)
isLastFromSender = getBoolean(R.styleable.MessageBubble_is_last, false)
}
@ -109,13 +109,14 @@ class MessageBubbleView @JvmOverloads constructor(context: Context, attrs: Attri
ConstraintSet().apply {
clone(bubbleView)
clear(R.id.viewStubContainer, ConstraintSet.END)
if (displayBorder) {
if (showTimeAsOverlay) {
connect(R.id.viewStubContainer, ConstraintSet.END, R.id.messageTimeView, ConstraintSet.START, 0)
} else {
connect(R.id.viewStubContainer, ConstraintSet.END, R.id.parent, ConstraintSet.END, 0)
}
applyTo(bubbleView)
}
}
private fun createBackgroundDrawable(): Drawable {
@ -147,12 +148,8 @@ class MessageBubbleView @JvmOverloads constructor(context: Context, attrs: Attri
.setBottomRightCorner(bottomCornerFamily, bottomRadius)
}
val shapeAppearanceModel = shapeAppearanceModelBuilder.build()
val shapeDrawable = MaterialShapeDrawable(shapeAppearanceModel)
if (displayBorder) {
shapeDrawable.fillColor = ContextCompat.getColorStateList(context, backgroundColor)
} else {
shapeDrawable.fillColor = ContextCompat.getColorStateList(context, android.R.color.transparent)
return MaterialShapeDrawable(shapeAppearanceModel).apply {
fillColor = ContextCompat.getColorStateList(context, backgroundColor)
}
return shapeDrawable
}
}

View file

@ -20,5 +20,5 @@ interface MessageViewConfiguration {
var isIncoming: Boolean
var isFirstFromSender: Boolean
var isLastFromSender: Boolean
var displayBorder: Boolean
var showTimeAsOverlay: Boolean
}

View file

@ -4,14 +4,12 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/palette_element_green"
tools:viewBindingIgnore="true">
<ImageView
android:id="@+id/messageThumbnailView"
android:layout_width="375dp"
android:layout_height="0dp"
android:layout_marginEnd="32dp"
android:contentDescription="@string/a11y_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"