Bubbles: continue exploration
This commit is contained in:
parent
ad63d3de1c
commit
f7c9b36cef
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<declare-styleable name="MessageBubble">
|
<declare-styleable name="MessageBubble">
|
||||||
<attr name="incoming_style" format="boolean" />
|
<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_first" format="boolean" />
|
||||||
<attr name="is_last" format="boolean" />
|
<attr name="is_last" format="boolean" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
@ -358,6 +358,9 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
|||||||
// Should be build if not cached or if model should be refreshed
|
// Should be build if not cached or if model should be refreshed
|
||||||
if (modelCache[position] == null || modelCache[position]?.isCacheable(partialState) == false) {
|
if (modelCache[position] == null || modelCache[position]?.isCacheable(partialState) == false) {
|
||||||
val prevEvent = currentSnapshot.prevOrNull(position)
|
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 {
|
val nextDisplayableEvent = currentSnapshot.subList(position + 1, currentSnapshot.size).firstOrNull {
|
||||||
timelineEventVisibilityHelper.shouldShowEvent(it, partialState.highlightedEventId)
|
timelineEventVisibilityHelper.shouldShowEvent(it, partialState.highlightedEventId)
|
||||||
}
|
}
|
||||||
@ -365,6 +368,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
|||||||
val params = TimelineItemFactoryParams(
|
val params = TimelineItemFactoryParams(
|
||||||
event = event,
|
event = event,
|
||||||
prevEvent = prevEvent,
|
prevEvent = prevEvent,
|
||||||
|
prevDisplayableEvent = prevDisplayableEvent,
|
||||||
nextEvent = nextEvent,
|
nextEvent = nextEvent,
|
||||||
nextDisplayableEvent = nextDisplayableEvent,
|
nextDisplayableEvent = nextDisplayableEvent,
|
||||||
partialState = partialState,
|
partialState = partialState,
|
||||||
|
@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
|||||||
data class TimelineItemFactoryParams(
|
data class TimelineItemFactoryParams(
|
||||||
val event: TimelineEvent,
|
val event: TimelineEvent,
|
||||||
val prevEvent: TimelineEvent? = null,
|
val prevEvent: TimelineEvent? = null,
|
||||||
|
val prevDisplayableEvent: TimelineEvent? = null,
|
||||||
val nextEvent: TimelineEvent? = null,
|
val nextEvent: TimelineEvent? = null,
|
||||||
val nextDisplayableEvent: TimelineEvent? = null,
|
val nextDisplayableEvent: TimelineEvent? = null,
|
||||||
val partialState: TimelineEventController.PartialState = TimelineEventController.PartialState(),
|
val partialState: TimelineEventController.PartialState = TimelineEventController.PartialState(),
|
||||||
|
@ -57,19 +57,21 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
|
|||||||
fun create(params: TimelineItemFactoryParams): MessageInformationData {
|
fun create(params: TimelineItemFactoryParams): MessageInformationData {
|
||||||
val event = params.event
|
val event = params.event
|
||||||
val nextDisplayableEvent = params.nextDisplayableEvent
|
val nextDisplayableEvent = params.nextDisplayableEvent
|
||||||
val prevEvent = params.prevEvent
|
val prevDisplayableEvent = params.prevDisplayableEvent
|
||||||
val eventId = event.eventId
|
val eventId = event.eventId
|
||||||
val isSentByMe = event.root.senderId == session.myUserId
|
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 roomSummary = params.partialState.roomSummary
|
||||||
|
|
||||||
val date = event.root.localDateTime()
|
val date = event.root.localDateTime()
|
||||||
val nextDate = nextDisplayableEvent?.root?.localDateTime()
|
val nextDate = nextDisplayableEvent?.root?.localDateTime()
|
||||||
val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate()
|
val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate()
|
||||||
|
|
||||||
val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60))
|
val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60))
|
||||||
?: false
|
?: 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 =
|
val showInformation =
|
||||||
(addDaySeparator ||
|
(addDaySeparator ||
|
||||||
event.senderInfo.avatarUrl != nextDisplayableEvent?.senderInfo?.avatarUrl ||
|
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) ||
|
nextDisplayableEvent.root.getClearType() !in listOf(EventType.MESSAGE, EventType.STICKER, EventType.ENCRYPTED) ||
|
||||||
isNextMessageReceivedMoreThanOneHourAgo ||
|
isNextMessageReceivedMoreThanOneHourAgo ||
|
||||||
isTileTypeMessage(nextDisplayableEvent) ||
|
isTileTypeMessage(nextDisplayableEvent) ||
|
||||||
nextDisplayableEvent.isEdition() ) && !isSentByMe
|
nextDisplayableEvent.isEdition()) && !isSentByMe
|
||||||
|
|
||||||
val time = dateFormatter.format(event.root.originServerTs, DateFormatKind.MESSAGE_SIMPLE)
|
val time = dateFormatter.format(event.root.originServerTs, DateFormatKind.MESSAGE_SIMPLE)
|
||||||
val e2eDecoration = getE2EDecoration(roomSummary, event)
|
val e2eDecoration = getE2EDecoration(roomSummary, event)
|
||||||
|
@ -29,7 +29,6 @@ import im.vector.app.core.epoxy.onClick
|
|||||||
import im.vector.app.core.files.LocalFilesHelper
|
import im.vector.app.core.files.LocalFilesHelper
|
||||||
import im.vector.app.core.glide.GlideApp
|
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.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.home.room.detail.timeline.view.MessageViewConfiguration
|
||||||
import im.vector.app.features.media.ImageContentRenderer
|
import im.vector.app.features.media.ImageContentRenderer
|
||||||
|
|
||||||
@ -72,7 +71,7 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
|
|||||||
holder.mediaContentView.onClick(attributes.itemClickListener)
|
holder.mediaContentView.onClick(attributes.itemClickListener)
|
||||||
holder.mediaContentView.setOnLongClickListener(attributes.itemLongClickListener)
|
holder.mediaContentView.setOnLongClickListener(attributes.itemLongClickListener)
|
||||||
holder.playContentView.visibility = if (playable) View.VISIBLE else View.GONE
|
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) {
|
override fun unbind(holder: Holder) {
|
||||||
|
@ -54,7 +54,7 @@ class MessageBubbleView @JvmOverloads constructor(context: Context, attrs: Attri
|
|||||||
render()
|
render()
|
||||||
}
|
}
|
||||||
|
|
||||||
override var displayBorder: Boolean = true
|
override var showTimeAsOverlay: Boolean = true
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
render()
|
render()
|
||||||
@ -66,7 +66,7 @@ class MessageBubbleView @JvmOverloads constructor(context: Context, attrs: Attri
|
|||||||
inflate(context, R.layout.view_message_bubble, this)
|
inflate(context, R.layout.view_message_bubble, this)
|
||||||
context.withStyledAttributes(attrs, R.styleable.MessageBubble) {
|
context.withStyledAttributes(attrs, R.styleable.MessageBubble) {
|
||||||
isIncoming = getBoolean(R.styleable.MessageBubble_incoming_style, false)
|
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)
|
isFirstFromSender = getBoolean(R.styleable.MessageBubble_is_first, false)
|
||||||
isLastFromSender = getBoolean(R.styleable.MessageBubble_is_last, false)
|
isLastFromSender = getBoolean(R.styleable.MessageBubble_is_last, false)
|
||||||
}
|
}
|
||||||
@ -109,13 +109,14 @@ class MessageBubbleView @JvmOverloads constructor(context: Context, attrs: Attri
|
|||||||
ConstraintSet().apply {
|
ConstraintSet().apply {
|
||||||
clone(bubbleView)
|
clone(bubbleView)
|
||||||
clear(R.id.viewStubContainer, ConstraintSet.END)
|
clear(R.id.viewStubContainer, ConstraintSet.END)
|
||||||
if (displayBorder) {
|
if (showTimeAsOverlay) {
|
||||||
connect(R.id.viewStubContainer, ConstraintSet.END, R.id.messageTimeView, ConstraintSet.START, 0)
|
connect(R.id.viewStubContainer, ConstraintSet.END, R.id.messageTimeView, ConstraintSet.START, 0)
|
||||||
} else {
|
} else {
|
||||||
connect(R.id.viewStubContainer, ConstraintSet.END, R.id.parent, ConstraintSet.END, 0)
|
connect(R.id.viewStubContainer, ConstraintSet.END, R.id.parent, ConstraintSet.END, 0)
|
||||||
}
|
}
|
||||||
applyTo(bubbleView)
|
applyTo(bubbleView)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createBackgroundDrawable(): Drawable {
|
private fun createBackgroundDrawable(): Drawable {
|
||||||
@ -147,12 +148,8 @@ class MessageBubbleView @JvmOverloads constructor(context: Context, attrs: Attri
|
|||||||
.setBottomRightCorner(bottomCornerFamily, bottomRadius)
|
.setBottomRightCorner(bottomCornerFamily, bottomRadius)
|
||||||
}
|
}
|
||||||
val shapeAppearanceModel = shapeAppearanceModelBuilder.build()
|
val shapeAppearanceModel = shapeAppearanceModelBuilder.build()
|
||||||
val shapeDrawable = MaterialShapeDrawable(shapeAppearanceModel)
|
return MaterialShapeDrawable(shapeAppearanceModel).apply {
|
||||||
if (displayBorder) {
|
fillColor = ContextCompat.getColorStateList(context, backgroundColor)
|
||||||
shapeDrawable.fillColor = ContextCompat.getColorStateList(context, backgroundColor)
|
|
||||||
} else {
|
|
||||||
shapeDrawable.fillColor = ContextCompat.getColorStateList(context, android.R.color.transparent)
|
|
||||||
}
|
}
|
||||||
return shapeDrawable
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,5 +20,5 @@ interface MessageViewConfiguration {
|
|||||||
var isIncoming: Boolean
|
var isIncoming: Boolean
|
||||||
var isFirstFromSender: Boolean
|
var isFirstFromSender: Boolean
|
||||||
var isLastFromSender: Boolean
|
var isLastFromSender: Boolean
|
||||||
var displayBorder: Boolean
|
var showTimeAsOverlay: Boolean
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,12 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@color/palette_element_green"
|
|
||||||
tools:viewBindingIgnore="true">
|
tools:viewBindingIgnore="true">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/messageThumbnailView"
|
android:id="@+id/messageThumbnailView"
|
||||||
android:layout_width="375dp"
|
android:layout_width="375dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_marginEnd="32dp"
|
|
||||||
android:contentDescription="@string/a11y_image"
|
android:contentDescription="@string/a11y_image"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0"
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user