mirror of
https://github.com/element-hq/element-android
synced 2024-10-27 05:06:59 +03:00
Merge pull request #685 from vector-im/feature/timeline_items
Feature/timeline items
This commit is contained in:
commit
fe17050580
15 changed files with 207 additions and 32 deletions
|
@ -9,6 +9,7 @@ Improvements 🙌:
|
||||||
- Search reaction by name or keyword in emoji picker
|
- Search reaction by name or keyword in emoji picker
|
||||||
- Handle code tags (#567)
|
- Handle code tags (#567)
|
||||||
- Support spoiler messages
|
- Support spoiler messages
|
||||||
|
- Support m.sticker and m.room.join_rules events in timeline
|
||||||
|
|
||||||
Other changes:
|
Other changes:
|
||||||
- Markdown set to off by default (#412)
|
- Markdown set to off by default (#412)
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* 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.matrix.android.api.session.room.model
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum for [RoomJoinRulesContent] : https://matrix.org/docs/spec/client_server/r0.4.0#m-room-join-rules
|
||||||
|
*/
|
||||||
|
enum class RoomJoinRules(val value: String) {
|
||||||
|
|
||||||
|
@Json(name = "public")
|
||||||
|
PUBLIC("public"),
|
||||||
|
|
||||||
|
@Json(name = "invite")
|
||||||
|
INVITE("invite"),
|
||||||
|
|
||||||
|
@Json(name = "knock")
|
||||||
|
KNOCK("knock"),
|
||||||
|
|
||||||
|
@Json(name = "private")
|
||||||
|
PRIVATE("private")
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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.matrix.android.api.session.room.model
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing the EventType.STATE_ROOM_JOIN_RULES state event content
|
||||||
|
*/
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class RoomJoinRulesContent(
|
||||||
|
@Json(name = "join_rule") val joinRules: RoomJoinRules? = null
|
||||||
|
)
|
|
@ -38,7 +38,7 @@ data class MessageImageContent(
|
||||||
/**
|
/**
|
||||||
* Metadata about the image referred to in url.
|
* Metadata about the image referred to in url.
|
||||||
*/
|
*/
|
||||||
@Json(name = "info") val info: ImageInfo? = null,
|
@Json(name = "info") override val info: ImageInfo? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required. Required if the file is unencrypted. The URL (typically MXC URI) to the image.
|
* Required. Required if the file is unencrypted. The URL (typically MXC URI) to the image.
|
||||||
|
@ -52,4 +52,4 @@ data class MessageImageContent(
|
||||||
* Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption.
|
* Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption.
|
||||||
*/
|
*/
|
||||||
@Json(name = "file") override val encryptedFileInfo: EncryptedFileInfo? = null
|
@Json(name = "file") override val encryptedFileInfo: EncryptedFileInfo? = null
|
||||||
) : MessageEncryptedContent
|
) : MessageImageInfoContent
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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.matrix.android.api.session.room.model.message
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A content with image information
|
||||||
|
*/
|
||||||
|
interface MessageImageInfoContent : MessageEncryptedContent {
|
||||||
|
val info: ImageInfo?
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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.matrix.android.api.session.room.model.message
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Content
|
||||||
|
import im.vector.matrix.android.api.session.room.model.relation.RelationDefaultContent
|
||||||
|
import im.vector.matrix.android.internal.crypto.model.rest.EncryptedFileInfo
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class MessageStickerContent(
|
||||||
|
/**
|
||||||
|
* Set in local, not from server
|
||||||
|
*/
|
||||||
|
override val type: String = MessageType.MSGTYPE_STICKER_LOCAL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required. A textual representation of the image. This could be the alt text of the image, the filename of the image,
|
||||||
|
* or some kind of content description for accessibility e.g. 'image attachment'.
|
||||||
|
*/
|
||||||
|
@Json(name = "body") override val body: String,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Metadata about the image referred to in url.
|
||||||
|
*/
|
||||||
|
@Json(name = "info") override val info: ImageInfo? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required. Required if the file is unencrypted. The URL (typically MXC URI) to the image.
|
||||||
|
*/
|
||||||
|
@Json(name = "url") override val url: String? = null,
|
||||||
|
|
||||||
|
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||||
|
@Json(name = "m.new_content") override val newContent: Content? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption.
|
||||||
|
*/
|
||||||
|
@Json(name = "file") override val encryptedFileInfo: EncryptedFileInfo? = null
|
||||||
|
) : MessageImageInfoContent
|
|
@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
||||||
import im.vector.matrix.android.api.session.room.model.ReadReceipt
|
import im.vector.matrix.android.api.session.room.model.ReadReceipt
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageStickerContent
|
||||||
import im.vector.matrix.android.api.session.room.model.message.isReply
|
import im.vector.matrix.android.api.session.room.model.message.isReply
|
||||||
import im.vector.matrix.android.api.util.ContentUtils.extractUsefulTextFromReply
|
import im.vector.matrix.android.api.util.ContentUtils.extractUsefulTextFromReply
|
||||||
import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent
|
import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent
|
||||||
|
@ -99,8 +100,14 @@ fun TimelineEvent.getEditedEventId(): String? {
|
||||||
/**
|
/**
|
||||||
* Get last MessageContent, after a possible edition
|
* Get last MessageContent, after a possible edition
|
||||||
*/
|
*/
|
||||||
fun TimelineEvent.getLastMessageContent(): MessageContent? = annotations?.editSummary?.aggregatedContent?.toModel()
|
fun TimelineEvent.getLastMessageContent(): MessageContent? {
|
||||||
|
return if (root.getClearType() == EventType.STICKER) {
|
||||||
|
root.getClearContent().toModel<MessageStickerContent>()
|
||||||
|
} else {
|
||||||
|
annotations?.editSummary?.aggregatedContent?.toModel()
|
||||||
?: root.getClearContent().toModel()
|
?: root.getClearContent().toModel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get last Message body, after a possible edition
|
* Get last Message body, after a possible edition
|
||||||
|
@ -110,7 +117,7 @@ fun TimelineEvent.getLastMessageBody(): String? {
|
||||||
|
|
||||||
if (lastMessageContent != null) {
|
if (lastMessageContent != null) {
|
||||||
return lastMessageContent.newContent?.toModel<MessageContent>()?.body
|
return lastMessageContent.newContent?.toModel<MessageContent>()?.body
|
||||||
?: lastMessageContent.body
|
?: lastMessageContent.body
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -877,7 +877,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
vectorBaseActivity.notImplemented("encrypted message click")
|
vectorBaseActivity.notImplemented("encrypted message click")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View) {
|
override fun onImageMessageClicked(messageImageContent: MessageImageInfoContent, mediaData: ImageContentRenderer.Data, view: View) {
|
||||||
// TODO Use navigator
|
// TODO Use navigator
|
||||||
|
|
||||||
val intent = ImageMediaViewerActivity.newIntent(vectorBaseActivity, mediaData, ViewCompat.getTransitionName(view))
|
val intent = ImageMediaViewerActivity.newIntent(vectorBaseActivity, mediaData, ViewCompat.getTransitionName(view))
|
||||||
|
|
|
@ -62,7 +62,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
||||||
fun onEventVisible(event: TimelineEvent)
|
fun onEventVisible(event: TimelineEvent)
|
||||||
fun onRoomCreateLinkClicked(url: String)
|
fun onRoomCreateLinkClicked(url: String)
|
||||||
fun onEncryptedMessageClicked(informationData: MessageInformationData, view: View)
|
fun onEncryptedMessageClicked(informationData: MessageInformationData, view: View)
|
||||||
fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View)
|
fun onImageMessageClicked(messageImageContent: MessageImageInfoContent, mediaData: ImageContentRenderer.Data, view: View)
|
||||||
fun onVideoMessageClicked(messageVideoContent: MessageVideoContent, mediaData: VideoContentRenderer.Data, view: View)
|
fun onVideoMessageClicked(messageVideoContent: MessageVideoContent, mediaData: VideoContentRenderer.Data, view: View)
|
||||||
fun onFileMessageClicked(eventId: String, messageFileContent: MessageFileContent)
|
fun onFileMessageClicked(eventId: String, messageFileContent: MessageFileContent)
|
||||||
fun onAudioMessageClicked(messageAudioContent: MessageAudioContent)
|
fun onAudioMessageClicked(messageAudioContent: MessageAudioContent)
|
||||||
|
|
|
@ -89,7 +89,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
return defaultItemFactory.create(malformedText, informationData, highlight, callback)
|
return defaultItemFactory.create(malformedText, informationData, highlight, callback)
|
||||||
}
|
}
|
||||||
if (messageContent.relatesTo?.type == RelationType.REPLACE
|
if (messageContent.relatesTo?.type == RelationType.REPLACE
|
||||||
|| event.isEncrypted() && event.root.content.toModel<EncryptedEventContent>()?.relatesTo?.type == RelationType.REPLACE
|
|| event.isEncrypted() && event.root.content.toModel<EncryptedEventContent>()?.relatesTo?.type == RelationType.REPLACE
|
||||||
) {
|
) {
|
||||||
// This is an edit event, we should it when debugging as a notice event
|
// This is an edit event, we should it when debugging as a notice event
|
||||||
return noticeItemFactory.create(event, highlight, readMarkerVisible, callback)
|
return noticeItemFactory.create(event, highlight, readMarkerVisible, callback)
|
||||||
|
@ -99,14 +99,14 @@ 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) {
|
return 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 MessageImageContent -> buildImageMessageItem(messageContent, informationData, highlight, callback, attributes)
|
is MessageImageInfoContent -> buildImageMessageItem(messageContent, informationData, highlight, callback, attributes)
|
||||||
is MessageNoticeContent -> buildNoticeMessageItem(messageContent, informationData, highlight, callback, attributes)
|
is MessageNoticeContent -> buildNoticeMessageItem(messageContent, informationData, highlight, callback, attributes)
|
||||||
is MessageVideoContent -> buildVideoMessageItem(messageContent, informationData, highlight, callback, attributes)
|
is MessageVideoContent -> buildVideoMessageItem(messageContent, informationData, highlight, callback, attributes)
|
||||||
is MessageFileContent -> buildFileMessageItem(messageContent, informationData, highlight, callback, attributes)
|
is MessageFileContent -> buildFileMessageItem(messageContent, informationData, highlight, callback, attributes)
|
||||||
is MessageAudioContent -> buildAudioMessageItem(messageContent, informationData, highlight, callback, attributes)
|
is MessageAudioContent -> buildAudioMessageItem(messageContent, informationData, highlight, callback, attributes)
|
||||||
else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback)
|
else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
return defaultItemFactory.create(text, informationData, highlight, callback)
|
return defaultItemFactory.create(text, informationData, highlight, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildImageMessageItem(messageContent: MessageImageContent,
|
private fun buildImageMessageItem(messageContent: MessageImageInfoContent,
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
informationData: MessageInformationData,
|
informationData: MessageInformationData,
|
||||||
highlight: Boolean,
|
highlight: Boolean,
|
||||||
|
@ -196,7 +196,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
val thumbnailData = ImageContentRenderer.Data(
|
val thumbnailData = ImageContentRenderer.Data(
|
||||||
filename = messageContent.body,
|
filename = messageContent.body,
|
||||||
url = messageContent.videoInfo?.thumbnailFile?.url
|
url = messageContent.videoInfo?.thumbnailFile?.url
|
||||||
?: messageContent.videoInfo?.thumbnailUrl,
|
?: messageContent.videoInfo?.thumbnailUrl,
|
||||||
elementToDecrypt = messageContent.videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
elementToDecrypt = messageContent.videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
||||||
height = messageContent.videoInfo?.height,
|
height = messageContent.videoInfo?.height,
|
||||||
maxHeight = maxHeight,
|
maxHeight = maxHeight,
|
||||||
|
@ -326,9 +326,9 @@ class MessageItemFactory @Inject constructor(
|
||||||
// nop
|
// nop
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
editStart,
|
editStart,
|
||||||
editEnd,
|
editEnd,
|
||||||
Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
|
Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
|
||||||
return spannable
|
return spannable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,23 +39,25 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me
|
||||||
|
|
||||||
val computedModel = try {
|
val computedModel = try {
|
||||||
when (event.root.getClearType()) {
|
when (event.root.getClearType()) {
|
||||||
EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, highlight, readMarkerVisible, callback)
|
EventType.STICKER,
|
||||||
|
EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, highlight, readMarkerVisible, callback)
|
||||||
// State and call
|
// State and call
|
||||||
EventType.STATE_ROOM_TOMBSTONE,
|
EventType.STATE_ROOM_TOMBSTONE,
|
||||||
EventType.STATE_ROOM_NAME,
|
EventType.STATE_ROOM_NAME,
|
||||||
EventType.STATE_ROOM_TOPIC,
|
EventType.STATE_ROOM_TOPIC,
|
||||||
EventType.STATE_ROOM_MEMBER,
|
EventType.STATE_ROOM_MEMBER,
|
||||||
|
EventType.STATE_ROOM_JOIN_RULES,
|
||||||
EventType.STATE_HISTORY_VISIBILITY,
|
EventType.STATE_HISTORY_VISIBILITY,
|
||||||
EventType.CALL_INVITE,
|
EventType.CALL_INVITE,
|
||||||
EventType.CALL_HANGUP,
|
EventType.CALL_HANGUP,
|
||||||
EventType.CALL_ANSWER,
|
EventType.CALL_ANSWER,
|
||||||
EventType.REACTION,
|
EventType.REACTION,
|
||||||
EventType.REDACTION,
|
EventType.REDACTION,
|
||||||
EventType.ENCRYPTION -> noticeItemFactory.create(event, highlight, readMarkerVisible, callback)
|
EventType.ENCRYPTION -> noticeItemFactory.create(event, highlight, readMarkerVisible, callback)
|
||||||
// State room create
|
// State room create
|
||||||
EventType.STATE_ROOM_CREATE -> roomCreateItemFactory.create(event, callback)
|
EventType.STATE_ROOM_CREATE -> roomCreateItemFactory.create(event, callback)
|
||||||
// Crypto
|
// Crypto
|
||||||
EventType.ENCRYPTED -> {
|
EventType.ENCRYPTED -> {
|
||||||
if (event.root.isRedacted()) {
|
if (event.root.isRedacted()) {
|
||||||
// Redacted event, let the MessageItemFactory handle it
|
// Redacted event, let the MessageItemFactory handle it
|
||||||
messageItemFactory.create(event, nextEvent, highlight, readMarkerVisible, callback)
|
messageItemFactory.create(event, nextEvent, highlight, readMarkerVisible, callback)
|
||||||
|
@ -65,9 +67,8 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unhandled event types (yet)
|
// Unhandled event types (yet)
|
||||||
EventType.STATE_ROOM_THIRD_PARTY_INVITE,
|
EventType.STATE_ROOM_THIRD_PARTY_INVITE -> defaultItemFactory.create(event, highlight, readMarkerVisible, callback)
|
||||||
EventType.STICKER -> defaultItemFactory.create(event, highlight, readMarkerVisible, callback)
|
else -> {
|
||||||
else -> {
|
|
||||||
Timber.v("Type ${event.root.getClearType()} not handled")
|
Timber.v("Type ${event.root.getClearType()} not handled")
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
import im.vector.matrix.android.api.session.room.model.Membership
|
import im.vector.matrix.android.api.session.room.model.Membership
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility
|
import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibilityContent
|
import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibilityContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.RoomJoinRules
|
||||||
|
import im.vector.matrix.android.api.session.room.model.RoomJoinRulesContent
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomNameContent
|
import im.vector.matrix.android.api.session.room.model.RoomNameContent
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomTopicContent
|
import im.vector.matrix.android.api.session.room.model.RoomTopicContent
|
||||||
|
@ -38,6 +40,7 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active
|
||||||
|
|
||||||
fun format(timelineEvent: TimelineEvent): CharSequence? {
|
fun format(timelineEvent: TimelineEvent): CharSequence? {
|
||||||
return when (val type = timelineEvent.root.getClearType()) {
|
return when (val type = timelineEvent.root.getClearType()) {
|
||||||
|
EventType.STATE_ROOM_JOIN_RULES -> formatJoinRulesEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName())
|
||||||
EventType.STATE_ROOM_NAME -> formatRoomNameEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName())
|
EventType.STATE_ROOM_NAME -> formatRoomNameEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName())
|
||||||
EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName())
|
EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName())
|
||||||
EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName())
|
EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(timelineEvent.root, timelineEvent.getDisambiguatedDisplayName())
|
||||||
|
@ -58,6 +61,7 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active
|
||||||
|
|
||||||
fun format(event: Event, senderName: String?): CharSequence? {
|
fun format(event: Event, senderName: String?): CharSequence? {
|
||||||
return when (val type = event.getClearType()) {
|
return when (val type = event.getClearType()) {
|
||||||
|
EventType.STATE_ROOM_JOIN_RULES -> formatJoinRulesEvent(event, senderName)
|
||||||
EventType.STATE_ROOM_NAME -> formatRoomNameEvent(event, senderName)
|
EventType.STATE_ROOM_NAME -> formatRoomNameEvent(event, senderName)
|
||||||
EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(event, senderName)
|
EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(event, senderName)
|
||||||
EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(event, senderName)
|
EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(event, senderName)
|
||||||
|
@ -220,4 +224,13 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun formatJoinRulesEvent(event: Event, senderName: String?): CharSequence? {
|
||||||
|
val content = event.getClearContent().toModel<RoomJoinRulesContent>() ?: return null
|
||||||
|
return when (content.joinRules) {
|
||||||
|
RoomJoinRules.INVITE -> stringProvider.getString(R.string.room_join_rules_invite, senderName)
|
||||||
|
RoomJoinRules.PUBLIC -> stringProvider.getString(R.string.room_join_rules_public, senderName)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,8 @@ object TimelineDisplayableEvents {
|
||||||
EventType.STATE_ROOM_THIRD_PARTY_INVITE,
|
EventType.STATE_ROOM_THIRD_PARTY_INVITE,
|
||||||
EventType.STICKER,
|
EventType.STICKER,
|
||||||
EventType.STATE_ROOM_CREATE,
|
EventType.STATE_ROOM_CREATE,
|
||||||
EventType.STATE_ROOM_TOMBSTONE
|
EventType.STATE_ROOM_TOMBSTONE,
|
||||||
|
EventType.STATE_ROOM_JOIN_RULES
|
||||||
)
|
)
|
||||||
|
|
||||||
val DEBUG_DISPLAYABLE_TYPES = DISPLAYABLE_TYPES + listOf(
|
val DEBUG_DISPLAYABLE_TYPES = DISPLAYABLE_TYPES + listOf(
|
||||||
|
|
|
@ -18,10 +18,9 @@ package im.vector.riotx.features.home.room.list
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
|
||||||
import im.vector.matrix.android.api.session.room.model.Membership
|
import im.vector.matrix.android.api.session.room.model.Membership
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.date.VectorDateFormatter
|
import im.vector.riotx.core.date.VectorDateFormatter
|
||||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||||
|
@ -97,9 +96,9 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte
|
||||||
latestFormattedEvent = if (latestEvent.root.isEncrypted()
|
latestFormattedEvent = if (latestEvent.root.isEncrypted()
|
||||||
&& latestEvent.root.mxDecryptionResult == null) {
|
&& latestEvent.root.mxDecryptionResult == null) {
|
||||||
stringProvider.getString(R.string.encrypted_message)
|
stringProvider.getString(R.string.encrypted_message)
|
||||||
} else if (latestEvent.root.getClearType() == EventType.MESSAGE) {
|
} else if (latestEvent.root.getClearType() == EventType.MESSAGE || latestEvent.root.getClearType() == EventType.STICKER) {
|
||||||
val senderName = latestEvent.getDisambiguatedDisplayName()
|
val senderName = latestEvent.getDisambiguatedDisplayName()
|
||||||
val content = latestEvent.root.getClearContent()?.toModel<MessageContent>()
|
val content = latestEvent.getLastMessageContent()
|
||||||
val message = content?.body ?: ""
|
val message = content?.body ?: ""
|
||||||
if (roomSummary.isDirect.not()) {
|
if (roomSummary.isDirect.not()) {
|
||||||
span {
|
span {
|
||||||
|
|
|
@ -19,4 +19,9 @@
|
||||||
|
|
||||||
<string name="help_long_click_on_room_for_more_options">Long click on a room to see more options</string>
|
<string name="help_long_click_on_room_for_more_options">Long click on a room to see more options</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="room_join_rules_public">%1$s made the room public to whoever knows the link.</string>
|
||||||
|
<string name="room_join_rules_invite">%1$s made the room invite only.</string>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue