forked from GitHub-Mirror/riotX-android
Create MessageInformationDataFactory for reusability
This commit is contained in:
parent
273c8a19b8
commit
a53e40e1ee
@ -29,6 +29,7 @@ import im.vector.riotredesign.features.home.room.detail.timeline.factory.*
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.util.MessageInformationDataFactory
|
||||
import im.vector.riotredesign.features.home.room.list.RoomSummaryController
|
||||
import im.vector.riotredesign.features.html.EventHtmlRenderer
|
||||
import org.koin.core.parameter.parametersOf
|
||||
@ -69,15 +70,22 @@ class HomeModule {
|
||||
val eventHtmlRenderer = EventHtmlRenderer(GlideApp.with(fragment), fragment.requireContext(), get())
|
||||
val noticeEventFormatter = get<NoticeEventFormatter>(parameters = { parametersOf(fragment) })
|
||||
val timelineMediaSizeProvider = TimelineMediaSizeProvider()
|
||||
val messageItemFactory = MessageItemFactory(colorProvider, timelineMediaSizeProvider,
|
||||
timelineDateFormatter, eventHtmlRenderer, get(), get())
|
||||
val messageInformationDataFactory = MessageInformationDataFactory(timelineDateFormatter, colorProvider)
|
||||
val messageItemFactory = MessageItemFactory(colorProvider,
|
||||
timelineMediaSizeProvider,
|
||||
eventHtmlRenderer,
|
||||
get(),
|
||||
messageInformationDataFactory,
|
||||
get())
|
||||
|
||||
val encryptedItemFactory = EncryptedItemFactory(messageInformationDataFactory, colorProvider, get())
|
||||
|
||||
val timelineItemFactory = TimelineItemFactory(
|
||||
messageItemFactory = messageItemFactory,
|
||||
noticeItemFactory = NoticeItemFactory(noticeEventFormatter),
|
||||
defaultItemFactory = DefaultItemFactory(),
|
||||
encryptionItemFactory = EncryptionItemFactory(get()),
|
||||
encryptedItemFactory = EncryptedItemFactory(get())
|
||||
encryptedItemFactory = encryptedItemFactory
|
||||
)
|
||||
TimelineEventController(timelineDateFormatter, timelineItemFactory, timelineMediaSizeProvider)
|
||||
}
|
||||
|
@ -16,28 +16,28 @@
|
||||
|
||||
package im.vector.riotredesign.features.home.room.detail.timeline.factory
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.style.StyleSpan
|
||||
import im.vector.matrix.android.api.session.crypto.MXCryptoError
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotredesign.core.resources.ColorProvider
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderAvatar
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderName
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem_
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.util.MessageInformationDataFactory
|
||||
import me.gujun.android.span.span
|
||||
|
||||
// This class handles timeline event who haven't been successfully decrypted
|
||||
class EncryptedItemFactory(private val stringProvider: StringProvider) {
|
||||
// This class handles timeline events who haven't been successfully decrypted
|
||||
class EncryptedItemFactory(private val messageInformationDataFactory: MessageInformationDataFactory,
|
||||
private val colorProvider: ColorProvider,
|
||||
private val stringProvider: StringProvider) {
|
||||
|
||||
fun create(event: TimelineEvent, nextEvent: TimelineEvent?): VectorEpoxyModel<*>? {
|
||||
event.root.eventId ?: return null
|
||||
|
||||
fun create(timelineEvent: TimelineEvent): VectorEpoxyModel<*>? {
|
||||
return when {
|
||||
EventType.ENCRYPTED == timelineEvent.root.getClearType() -> {
|
||||
val cryptoError = timelineEvent.root.mCryptoError
|
||||
EventType.ENCRYPTED == event.root.getClearType() -> {
|
||||
val cryptoError = event.root.mCryptoError
|
||||
val errorDescription =
|
||||
if (cryptoError?.code == MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE) {
|
||||
stringProvider.getString(R.string.notice_crypto_error_unkwown_inbound_session_id)
|
||||
@ -46,22 +46,21 @@ class EncryptedItemFactory(private val stringProvider: StringProvider) {
|
||||
}
|
||||
|
||||
val message = stringProvider.getString(R.string.notice_crypto_unable_to_decrypt, errorDescription)
|
||||
val spannableStr = SpannableString(message)
|
||||
spannableStr.setSpan(StyleSpan(Typeface.ITALIC), 0, message.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
val spannableStr = span(message) {
|
||||
textStyle = "italic"
|
||||
textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary)
|
||||
}
|
||||
|
||||
// TODO This is not correct format for error, change it
|
||||
val informationData = MessageInformationData(
|
||||
eventId = timelineEvent.root.eventId ?: "?",
|
||||
senderId = timelineEvent.root.sender ?: "",
|
||||
sendState = timelineEvent.sendState,
|
||||
avatarUrl = timelineEvent.senderAvatar(),
|
||||
memberName = timelineEvent.senderName(),
|
||||
showInformation = false
|
||||
)
|
||||
return NoticeItem_()
|
||||
.noticeText(spannableStr)
|
||||
val informationData = messageInformationDataFactory.create(event, nextEvent)
|
||||
|
||||
return MessageTextItem_()
|
||||
.message(spannableStr)
|
||||
.informationData(informationData)
|
||||
|
||||
// TODO Handle click on this event
|
||||
}
|
||||
else -> null
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ import android.text.style.RelativeSizeSpan
|
||||
import android.view.View
|
||||
import im.vector.matrix.android.api.permalinks.MatrixLinkify
|
||||
import im.vector.matrix.android.api.permalinks.MatrixPermalinkSpan
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.RelationType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary
|
||||
@ -35,16 +34,14 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.riotredesign.EmojiCompatFontProvider
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotredesign.core.extensions.localDateTime
|
||||
import im.vector.riotredesign.core.linkify.VectorLinkify
|
||||
import im.vector.riotredesign.core.resources.ColorProvider
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
import im.vector.riotredesign.core.utils.DebouncedClickListener
|
||||
import im.vector.riotredesign.features.home.getColorFromUserId
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.*
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.util.MessageInformationDataFactory
|
||||
import im.vector.riotredesign.features.html.EventHtmlRenderer
|
||||
import im.vector.riotredesign.features.media.ImageContentRenderer
|
||||
import im.vector.riotredesign.features.media.VideoContentRenderer
|
||||
@ -52,50 +49,18 @@ import me.gujun.android.span.span
|
||||
|
||||
class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
private val timelineMediaSizeProvider: TimelineMediaSizeProvider,
|
||||
private val timelineDateFormatter: TimelineDateFormatter,
|
||||
private val htmlRenderer: EventHtmlRenderer,
|
||||
private val stringProvider: StringProvider,
|
||||
private val messageInformationDataFactory: MessageInformationDataFactory,
|
||||
private val emojiCompatFontProvider: EmojiCompatFontProvider) {
|
||||
|
||||
fun create(event: TimelineEvent,
|
||||
nextEvent: TimelineEvent?,
|
||||
callback: TimelineEventController.Callback?
|
||||
): VectorEpoxyModel<*>? {
|
||||
event.root.eventId ?: return null
|
||||
|
||||
val eventId = event.root.eventId ?: return null
|
||||
|
||||
val date = event.root.localDateTime()
|
||||
val nextDate = nextEvent?.root?.localDateTime()
|
||||
val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate()
|
||||
val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60))
|
||||
?: false
|
||||
|
||||
val showInformation = addDaySeparator
|
||||
|| event.senderAvatar != nextEvent?.senderAvatar
|
||||
|| event.senderName != nextEvent?.senderName
|
||||
|| nextEvent?.root?.getClearType() != EventType.MESSAGE
|
||||
|| isNextMessageReceivedMoreThanOneHourAgo
|
||||
|
||||
val time = timelineDateFormatter.formatMessageHour(date)
|
||||
val avatarUrl = event.senderAvatar
|
||||
val memberName = event.senderName ?: event.root.sender ?: ""
|
||||
val formattedMemberName = span(memberName) {
|
||||
textColor = colorProvider.getColor(getColorFromUserId(event.root.sender
|
||||
?: ""))
|
||||
}
|
||||
val hasBeenEdited = event.annotations?.editSummary != null
|
||||
val informationData = MessageInformationData(eventId = eventId,
|
||||
senderId = event.root.sender ?: "",
|
||||
sendState = event.sendState,
|
||||
time = time,
|
||||
avatarUrl = avatarUrl,
|
||||
memberName = formattedMemberName,
|
||||
showInformation = showInformation,
|
||||
orderedReactionList = event.annotations?.reactionsSummary?.map {
|
||||
ReactionInfoData(it.key, it.count, it.addedByMe, it.localEchoEvents.isEmpty())
|
||||
},
|
||||
hasBeenEdited = hasBeenEdited
|
||||
)
|
||||
val informationData = messageInformationDataFactory.create(event, nextEvent)
|
||||
|
||||
if (event.root.unsignedData?.redactedEvent != null) {
|
||||
//message is redacted
|
||||
@ -117,13 +82,11 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
return when (messageContent) {
|
||||
is MessageEmoteContent -> buildEmoteMessageItem(messageContent,
|
||||
informationData,
|
||||
hasBeenEdited,
|
||||
event.annotations?.editSummary,
|
||||
callback)
|
||||
is MessageTextContent -> buildTextMessageItem(event.sendState,
|
||||
messageContent,
|
||||
informationData,
|
||||
hasBeenEdited,
|
||||
event.annotations?.editSummary,
|
||||
callback
|
||||
)
|
||||
@ -266,7 +229,6 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
private fun buildTextMessageItem(sendState: SendState,
|
||||
messageContent: MessageTextContent,
|
||||
informationData: MessageInformationData,
|
||||
hasBeenEdited: Boolean,
|
||||
editSummary: EditAggregatedSummary?,
|
||||
callback: TimelineEventController.Callback?): MessageTextItem? {
|
||||
|
||||
@ -278,7 +240,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
|
||||
return MessageTextItem_()
|
||||
.apply {
|
||||
if (hasBeenEdited) {
|
||||
if (informationData.hasBeenEdited) {
|
||||
val spannable = annotateWithEdited(linkifiedBody, callback, informationData, editSummary)
|
||||
message(spannable)
|
||||
} else {
|
||||
@ -368,7 +330,6 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
|
||||
private fun buildEmoteMessageItem(messageContent: MessageEmoteContent,
|
||||
informationData: MessageInformationData,
|
||||
hasBeenEdited: Boolean,
|
||||
editSummary: EditAggregatedSummary?,
|
||||
callback: TimelineEventController.Callback?): MessageTextItem? {
|
||||
|
||||
@ -378,7 +339,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
}
|
||||
return MessageTextItem_()
|
||||
.apply {
|
||||
if (hasBeenEdited) {
|
||||
if (informationData.hasBeenEdited) {
|
||||
val spannable = annotateWithEdited(message, callback, informationData, editSummary)
|
||||
message(spannable)
|
||||
} else {
|
||||
|
@ -53,7 +53,7 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
|
||||
|
||||
// Crypto
|
||||
EventType.ENCRYPTION -> encryptionItemFactory.create(event)
|
||||
EventType.ENCRYPTED -> encryptedItemFactory.create(event)
|
||||
EventType.ENCRYPTED -> encryptedItemFactory.create(event, nextEvent)
|
||||
|
||||
// Unhandled event types (yet)
|
||||
EventType.STATE_ROOM_THIRD_PARTY_INVITE,
|
||||
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2019 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.riotredesign.features.home.room.detail.timeline.util
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.riotredesign.core.extensions.localDateTime
|
||||
import im.vector.riotredesign.core.resources.ColorProvider
|
||||
import im.vector.riotredesign.features.home.getColorFromUserId
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderAvatar
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.ReactionInfoData
|
||||
import me.gujun.android.span.span
|
||||
|
||||
/**
|
||||
* This class compute if data of an event (such has avatar, display name, ...) should be displayed, depending on the previous event in the timeline
|
||||
*/
|
||||
class MessageInformationDataFactory(private val timelineDateFormatter: TimelineDateFormatter,
|
||||
private val colorProvider: ColorProvider) {
|
||||
|
||||
fun create(event: TimelineEvent, nextEvent: TimelineEvent?): MessageInformationData {
|
||||
// Non nullability has been tested before
|
||||
val eventId = event.root.eventId!!
|
||||
|
||||
val date = event.root.localDateTime()
|
||||
|
||||
val nextDate = nextEvent?.root?.localDateTime()
|
||||
val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate()
|
||||
val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60))
|
||||
?: false
|
||||
val showInformation =
|
||||
addDaySeparator
|
||||
|| event.senderAvatar != nextEvent?.senderAvatar
|
||||
|| event.senderName != nextEvent?.senderName
|
||||
|| (nextEvent?.root?.getClearType() != EventType.MESSAGE && nextEvent?.root?.getClearType() != EventType.ENCRYPTED)
|
||||
|| isNextMessageReceivedMoreThanOneHourAgo
|
||||
|
||||
val time = timelineDateFormatter.formatMessageHour(date)
|
||||
val avatarUrl = event.senderAvatar()
|
||||
val memberName = event.senderName ?: event.root.sender ?: ""
|
||||
val formattedMemberName = span(memberName) {
|
||||
textColor = colorProvider.getColor(getColorFromUserId(event.root.sender
|
||||
?: ""))
|
||||
}
|
||||
|
||||
val hasBeenEdited = event.annotations?.editSummary != null
|
||||
|
||||
return MessageInformationData(
|
||||
eventId = eventId,
|
||||
senderId = event.root.sender ?: "",
|
||||
sendState = event.sendState,
|
||||
time = time,
|
||||
avatarUrl = avatarUrl,
|
||||
memberName = formattedMemberName,
|
||||
showInformation = showInformation,
|
||||
orderedReactionList = event.annotations?.reactionsSummary?.map {
|
||||
ReactionInfoData(it.key, it.count, it.addedByMe, it.localEchoEvents.isEmpty())
|
||||
},
|
||||
hasBeenEdited = hasBeenEdited
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user