mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-18 21:10:02 +03:00
Bubbles: start adding "theming" mechanism
This commit is contained in:
parent
f7c9b36cef
commit
af542a8243
10 changed files with 212 additions and 49 deletions
|
@ -108,6 +108,7 @@ class EncryptedItemFactory @Inject constructor(private val messageInformationDat
|
||||||
val informationData = messageInformationDataFactory.create(params)
|
val informationData = messageInformationDataFactory.create(params)
|
||||||
val attributes = attributesFactory.create(event.root.content.toModel<EncryptedEventContent>(), informationData, params.callback)
|
val attributes = attributesFactory.create(event.root.content.toModel<EncryptedEventContent>(), informationData, params.callback)
|
||||||
return MessageTextItem_()
|
return MessageTextItem_()
|
||||||
|
.layout(informationData.messageLayout.layoutRes)
|
||||||
.leftGuideline(avatarSizeProvider.leftGuideline)
|
.leftGuideline(avatarSizeProvider.leftGuideline)
|
||||||
.highlighted(params.isHighlighted)
|
.highlighted(params.isHighlighted)
|
||||||
.attributes(attributes)
|
.attributes(attributes)
|
||||||
|
|
|
@ -154,7 +154,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
|
|
||||||
// val all = event.root.toContent()
|
// val all = event.root.toContent()
|
||||||
// val ev = all.toModel<Event>()
|
// val ev = all.toModel<Event>()
|
||||||
return when (messageContent) {
|
val messageItem = when (messageContent) {
|
||||||
is MessageEmoteContent -> buildEmoteMessageItem(messageContent, informationData, highlight, callback, attributes)
|
is MessageEmoteContent -> buildEmoteMessageItem(messageContent, informationData, highlight, callback, attributes)
|
||||||
is MessageTextContent -> buildItemForTextContent(messageContent, informationData, highlight, callback, attributes)
|
is MessageTextContent -> buildItemForTextContent(messageContent, informationData, highlight, callback, attributes)
|
||||||
is MessageImageInfoContent -> buildImageMessageItem(messageContent, informationData, highlight, callback, attributes)
|
is MessageImageInfoContent -> buildImageMessageItem(messageContent, informationData, highlight, callback, attributes)
|
||||||
|
@ -172,6 +172,9 @@ class MessageItemFactory @Inject constructor(
|
||||||
is MessagePollContent -> buildPollContent(messageContent, informationData, highlight, callback, attributes)
|
is MessagePollContent -> buildPollContent(messageContent, informationData, highlight, callback, attributes)
|
||||||
else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback, attributes)
|
else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback, attributes)
|
||||||
}
|
}
|
||||||
|
return messageItem?.apply {
|
||||||
|
layout(informationData.messageLayout.layoutRes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildPollContent(pollContent: MessagePollContent,
|
private fun buildPollContent(pollContent: MessagePollContent,
|
||||||
|
@ -389,13 +392,6 @@ class MessageItemFactory @Inject constructor(
|
||||||
allowNonMxcUrls = informationData.sendState.isSending()
|
allowNonMxcUrls = informationData.sendState.isSending()
|
||||||
)
|
)
|
||||||
return MessageImageVideoItem_()
|
return MessageImageVideoItem_()
|
||||||
.layout(
|
|
||||||
if (informationData.sentByMe) {
|
|
||||||
R.layout.item_timeline_event_bubble_outgoing_base
|
|
||||||
} else {
|
|
||||||
R.layout.item_timeline_event_bubble_incoming_base
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.attributes(attributes)
|
.attributes(attributes)
|
||||||
.leftGuideline(avatarSizeProvider.leftGuideline)
|
.leftGuideline(avatarSizeProvider.leftGuideline)
|
||||||
.imageContentRenderer(imageContentRenderer)
|
.imageContentRenderer(imageContentRenderer)
|
||||||
|
@ -517,13 +513,6 @@ class MessageItemFactory @Inject constructor(
|
||||||
linkifiedBody
|
linkifiedBody
|
||||||
}.toEpoxyCharSequence()
|
}.toEpoxyCharSequence()
|
||||||
)
|
)
|
||||||
.layout(
|
|
||||||
if (informationData.sentByMe) {
|
|
||||||
R.layout.item_timeline_event_bubble_outgoing_base
|
|
||||||
} else {
|
|
||||||
R.layout.item_timeline_event_bubble_incoming_base
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.useBigFont(linkifiedBody.length <= MAX_NUMBER_OF_EMOJI_FOR_BIG_FONT * 2 && containsOnlyEmojis(linkifiedBody.toString()))
|
.useBigFont(linkifiedBody.length <= MAX_NUMBER_OF_EMOJI_FOR_BIG_FONT * 2 && containsOnlyEmojis(linkifiedBody.toString()))
|
||||||
.bindingOptions(bindingOptions)
|
.bindingOptions(bindingOptions)
|
||||||
.searchForPills(isFormatted)
|
.searchForPills(isFormatted)
|
||||||
|
|
|
@ -17,14 +17,22 @@
|
||||||
package im.vector.app.features.home.room.detail.timeline.helper
|
package im.vector.app.features.home.room.detail.timeline.helper
|
||||||
|
|
||||||
import im.vector.app.core.utils.DimensionConverter
|
import im.vector.app.core.utils.DimensionConverter
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.style.TimelineLayoutSettings
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.style.TimelineLayoutSettingsProvider
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AvatarSizeProvider @Inject constructor(private val dimensionConverter: DimensionConverter) {
|
class AvatarSizeProvider @Inject constructor(private val dimensionConverter: DimensionConverter,
|
||||||
|
private val layoutSettingsProvider: TimelineLayoutSettingsProvider) {
|
||||||
|
|
||||||
private val avatarStyle = AvatarStyle.X_SMALL
|
private val avatarStyle by lazy {
|
||||||
|
when (layoutSettingsProvider.getLayoutSettings()) {
|
||||||
|
TimelineLayoutSettings.MODERN -> AvatarStyle.SMALL
|
||||||
|
TimelineLayoutSettings.BUBBLE -> AvatarStyle.BUBBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val leftGuideline: Int by lazy {
|
val leftGuideline: Int by lazy {
|
||||||
dimensionConverter.dpToPx(avatarStyle.avatarSizeDP + 4)
|
dimensionConverter.dpToPx(avatarStyle.avatarSizeDP + avatarStyle.marginDP)
|
||||||
}
|
}
|
||||||
|
|
||||||
val avatarSize: Int by lazy {
|
val avatarSize: Int by lazy {
|
||||||
|
@ -33,12 +41,12 @@ class AvatarSizeProvider @Inject constructor(private val dimensionConverter: Dim
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
enum class AvatarStyle(val avatarSizeDP: Int) {
|
enum class AvatarStyle(val avatarSizeDP: Int, val marginDP: Int) {
|
||||||
BIG(50),
|
BIG(50, 8),
|
||||||
MEDIUM(40),
|
MEDIUM(40, 8),
|
||||||
SMALL(30),
|
SMALL(30, 8),
|
||||||
X_SMALL(28),
|
BUBBLE(28, 4),
|
||||||
NONE(0)
|
NONE(0, 8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ import im.vector.app.features.home.room.detail.timeline.item.PollVoteSummaryData
|
||||||
import im.vector.app.features.home.room.detail.timeline.item.ReactionInfoData
|
import im.vector.app.features.home.room.detail.timeline.item.ReactionInfoData
|
||||||
import im.vector.app.features.home.room.detail.timeline.item.ReferencesInfoData
|
import im.vector.app.features.home.room.detail.timeline.item.ReferencesInfoData
|
||||||
import im.vector.app.features.home.room.detail.timeline.item.SendStateDecoration
|
import im.vector.app.features.home.room.detail.timeline.item.SendStateDecoration
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayoutFactory
|
||||||
import org.matrix.android.sdk.api.crypto.VerificationState
|
import org.matrix.android.sdk.api.crypto.VerificationState
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
@ -41,7 +41,6 @@ import org.matrix.android.sdk.api.session.room.send.SendState
|
||||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||||
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
||||||
import org.matrix.android.sdk.api.session.room.timeline.hasBeenEdited
|
import org.matrix.android.sdk.api.session.room.timeline.hasBeenEdited
|
||||||
import org.matrix.android.sdk.api.session.room.timeline.isEdition
|
|
||||||
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
|
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -51,8 +50,7 @@ import javax.inject.Inject
|
||||||
*/
|
*/
|
||||||
class MessageInformationDataFactory @Inject constructor(private val session: Session,
|
class MessageInformationDataFactory @Inject constructor(private val session: Session,
|
||||||
private val dateFormatter: VectorDateFormatter,
|
private val dateFormatter: VectorDateFormatter,
|
||||||
private val visibilityHelper: TimelineEventVisibilityHelper,
|
private val messageLayoutFactory: TimelineMessageLayoutFactory) {
|
||||||
private val vectorPreferences: VectorPreferences) {
|
|
||||||
|
|
||||||
fun create(params: TimelineItemFactoryParams): MessageInformationData {
|
fun create(params: TimelineItemFactoryParams): MessageInformationData {
|
||||||
val event = params.event
|
val event = params.event
|
||||||
|
@ -66,21 +64,9 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
|
||||||
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))
|
|
||||||
?: false
|
|
||||||
|
|
||||||
val isFirstFromThisSender = nextDisplayableEvent?.root?.senderId != event.root.senderId || addDaySeparator
|
val isFirstFromThisSender = nextDisplayableEvent?.root?.senderId != event.root.senderId || addDaySeparator
|
||||||
val isLastFromThisSender = prevDisplayableEvent?.root?.senderId != event.root.senderId || prevDisplayableEvent?.root?.localDateTime()?.toLocalDate() != date.toLocalDate()
|
val isLastFromThisSender = prevDisplayableEvent?.root?.senderId != event.root.senderId || prevDisplayableEvent?.root?.localDateTime()?.toLocalDate() != date.toLocalDate()
|
||||||
|
|
||||||
val showInformation =
|
|
||||||
(addDaySeparator ||
|
|
||||||
event.senderInfo.avatarUrl != nextDisplayableEvent?.senderInfo?.avatarUrl ||
|
|
||||||
event.senderInfo.disambiguatedDisplayName != nextDisplayableEvent?.senderInfo?.disambiguatedDisplayName ||
|
|
||||||
nextDisplayableEvent.root.getClearType() !in listOf(EventType.MESSAGE, EventType.STICKER, EventType.ENCRYPTED) ||
|
|
||||||
isNextMessageReceivedMoreThanOneHourAgo ||
|
|
||||||
isTileTypeMessage(nextDisplayableEvent) ||
|
|
||||||
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)
|
||||||
|
|
||||||
|
@ -95,6 +81,8 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
|
||||||
SendStateDecoration.NONE
|
SendStateDecoration.NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val messageLayout = messageLayoutFactory.create(params)
|
||||||
|
|
||||||
return MessageInformationData(
|
return MessageInformationData(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
senderId = event.root.senderId ?: "",
|
senderId = event.root.senderId ?: "",
|
||||||
|
@ -103,9 +91,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
|
||||||
ageLocalTS = event.root.ageLocalTs,
|
ageLocalTS = event.root.ageLocalTs,
|
||||||
avatarUrl = event.senderInfo.avatarUrl,
|
avatarUrl = event.senderInfo.avatarUrl,
|
||||||
memberName = event.senderInfo.disambiguatedDisplayName,
|
memberName = event.senderInfo.disambiguatedDisplayName,
|
||||||
showAvatar = showInformation,
|
messageLayout = messageLayout,
|
||||||
showDisplayName = showInformation,
|
|
||||||
showTimestamp = true,
|
|
||||||
orderedReactionList = event.annotations?.reactionsSummary
|
orderedReactionList = event.annotations?.reactionsSummary
|
||||||
// ?.filter { isSingleEmoji(it.key) }
|
// ?.filter { isSingleEmoji(it.key) }
|
||||||
?.map {
|
?.map {
|
||||||
|
|
|
@ -62,7 +62,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
|
||||||
|
|
||||||
override fun bind(holder: H) {
|
override fun bind(holder: H) {
|
||||||
super.bind(holder)
|
super.bind(holder)
|
||||||
if (attributes.informationData.showAvatar) {
|
if (attributes.informationData.messageLayout.showAvatar) {
|
||||||
holder.avatarImageView.layoutParams = holder.avatarImageView.layoutParams?.apply {
|
holder.avatarImageView.layoutParams = holder.avatarImageView.layoutParams?.apply {
|
||||||
height = attributes.avatarSize
|
height = attributes.avatarSize
|
||||||
width = attributes.avatarSize
|
width = attributes.avatarSize
|
||||||
|
@ -76,7 +76,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
|
||||||
holder.avatarImageView.setOnLongClickListener(null)
|
holder.avatarImageView.setOnLongClickListener(null)
|
||||||
holder.avatarImageView.isVisible = false
|
holder.avatarImageView.isVisible = false
|
||||||
}
|
}
|
||||||
if (attributes.informationData.showDisplayName) {
|
if (attributes.informationData.messageLayout.showDisplayName) {
|
||||||
holder.memberNameView.isVisible = true
|
holder.memberNameView.isVisible = true
|
||||||
holder.memberNameView.text = attributes.informationData.memberName
|
holder.memberNameView.text = attributes.informationData.memberName
|
||||||
holder.memberNameView.setTextColor(attributes.getMemberNameColor())
|
holder.memberNameView.setTextColor(attributes.getMemberNameColor())
|
||||||
|
@ -87,7 +87,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
|
||||||
holder.memberNameView.setOnLongClickListener(null)
|
holder.memberNameView.setOnLongClickListener(null)
|
||||||
holder.memberNameView.isVisible = false
|
holder.memberNameView.isVisible = false
|
||||||
}
|
}
|
||||||
if (attributes.informationData.showTimestamp) {
|
if (attributes.informationData.messageLayout.showTimestamp) {
|
||||||
holder.timeView.isVisible = true
|
holder.timeView.isVisible = true
|
||||||
holder.timeView.text = attributes.informationData.time
|
holder.timeView.text = attributes.informationData.time
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package im.vector.app.features.home.room.detail.timeline.item
|
package im.vector.app.features.home.room.detail.timeline.item
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import org.matrix.android.sdk.api.crypto.VerificationState
|
import org.matrix.android.sdk.api.crypto.VerificationState
|
||||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||||
|
@ -31,9 +32,7 @@ data class MessageInformationData(
|
||||||
val ageLocalTS: Long?,
|
val ageLocalTS: Long?,
|
||||||
val avatarUrl: String?,
|
val avatarUrl: String?,
|
||||||
val memberName: CharSequence? = null,
|
val memberName: CharSequence? = null,
|
||||||
val showAvatar: Boolean,
|
val messageLayout: TimelineMessageLayout,
|
||||||
val showDisplayName: Boolean,
|
|
||||||
val showTimestamp: Boolean,
|
|
||||||
/*List of reactions (emoji,count,isSelected)*/
|
/*List of reactions (emoji,count,isSelected)*/
|
||||||
val orderedReactionList: List<ReactionInfoData>? = null,
|
val orderedReactionList: List<ReactionInfoData>? = null,
|
||||||
val pollResponseAggregatedSummary: PollResponseData? = null,
|
val pollResponseAggregatedSummary: PollResponseData? = null,
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.detail.timeline.style
|
||||||
|
|
||||||
|
enum class TimelineLayoutSettings {
|
||||||
|
MODERN,
|
||||||
|
BUBBLE
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.detail.timeline.style
|
||||||
|
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class TimelineLayoutSettingsProvider @Inject constructor() {
|
||||||
|
|
||||||
|
fun getLayoutSettings(): TimelineLayoutSettings {
|
||||||
|
return TimelineLayoutSettings.BUBBLE
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.detail.timeline.style
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import im.vector.app.R
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
sealed interface TimelineMessageLayout : Parcelable {
|
||||||
|
val layoutRes: Int
|
||||||
|
val showAvatar: Boolean
|
||||||
|
val showDisplayName: Boolean
|
||||||
|
val showTimestamp: Boolean
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class Modern(override val showAvatar: Boolean,
|
||||||
|
override val showDisplayName: Boolean,
|
||||||
|
override val showTimestamp: Boolean,
|
||||||
|
override val layoutRes: Int = R.layout.item_timeline_event_base) : TimelineMessageLayout
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class Bubble(override val showAvatar: Boolean,
|
||||||
|
override val showDisplayName: Boolean,
|
||||||
|
override val showTimestamp: Boolean = true,
|
||||||
|
val isIncoming: Boolean,
|
||||||
|
val isFirstFromThisSender: Boolean,
|
||||||
|
val isLastFromThisSender: Boolean,
|
||||||
|
override val layoutRes: Int = if (isIncoming) R.layout.item_timeline_event_bubble_incoming_base else R.layout.item_timeline_event_bubble_outgoing_base,
|
||||||
|
) : TimelineMessageLayout
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.detail.timeline.style
|
||||||
|
|
||||||
|
import im.vector.app.core.extensions.localDateTime
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.factory.TimelineItemFactoryParams
|
||||||
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||||
|
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.timeline.isEdition
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class TimelineMessageLayoutFactory @Inject constructor(private val session: Session,
|
||||||
|
private val layoutSettingsProvider: TimelineLayoutSettingsProvider,
|
||||||
|
private val vectorPreferences: VectorPreferences) {
|
||||||
|
|
||||||
|
fun create(params: TimelineItemFactoryParams): TimelineMessageLayout {
|
||||||
|
|
||||||
|
val event = params.event
|
||||||
|
val nextDisplayableEvent = params.nextDisplayableEvent
|
||||||
|
val prevDisplayableEvent = params.prevDisplayableEvent
|
||||||
|
val isSentByMe = event.root.senderId == session.myUserId
|
||||||
|
|
||||||
|
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 showInformation =
|
||||||
|
(addDaySeparator ||
|
||||||
|
event.senderInfo.avatarUrl != nextDisplayableEvent?.senderInfo?.avatarUrl ||
|
||||||
|
event.senderInfo.disambiguatedDisplayName != nextDisplayableEvent?.senderInfo?.disambiguatedDisplayName ||
|
||||||
|
nextDisplayableEvent.root.getClearType() !in listOf(EventType.MESSAGE, EventType.STICKER, EventType.ENCRYPTED) ||
|
||||||
|
isNextMessageReceivedMoreThanOneHourAgo ||
|
||||||
|
isTileTypeMessage(nextDisplayableEvent) ||
|
||||||
|
nextDisplayableEvent.isEdition()) && !isSentByMe
|
||||||
|
|
||||||
|
val messageLayout = when (layoutSettingsProvider.getLayoutSettings()) {
|
||||||
|
TimelineLayoutSettings.MODERN -> TimelineMessageLayout.Modern(showInformation, showInformation, showInformation || vectorPreferences.alwaysShowTimeStamps())
|
||||||
|
TimelineLayoutSettings.BUBBLE -> {
|
||||||
|
val isFirstFromThisSender = nextDisplayableEvent?.root?.senderId != event.root.senderId || addDaySeparator
|
||||||
|
val isLastFromThisSender = prevDisplayableEvent?.root?.senderId != event.root.senderId || prevDisplayableEvent?.root?.localDateTime()?.toLocalDate() != date.toLocalDate()
|
||||||
|
TimelineMessageLayout.Bubble(
|
||||||
|
showAvatar = showInformation,
|
||||||
|
showDisplayName = showInformation,
|
||||||
|
isIncoming = !isSentByMe,
|
||||||
|
isFirstFromThisSender = isFirstFromThisSender,
|
||||||
|
isLastFromThisSender = isLastFromThisSender
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return messageLayout
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tiles type message never show the sender information (like verification request), so we should repeat it for next message
|
||||||
|
* even if same sender
|
||||||
|
*/
|
||||||
|
private fun isTileTypeMessage(event: TimelineEvent?): Boolean {
|
||||||
|
return when (event?.root?.getClearType()) {
|
||||||
|
EventType.KEY_VERIFICATION_DONE,
|
||||||
|
EventType.KEY_VERIFICATION_CANCEL -> true
|
||||||
|
EventType.MESSAGE -> {
|
||||||
|
event.getLastMessageContent() is MessageVerificationRequestContent
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue