forked from GitHub-Mirror/riotX-android
Support message edition
This commit is contained in:
parent
2581bf69e0
commit
8cb884f10e
@ -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
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.Content
|
||||
|
||||
data class EditAggregatedSummary(
|
||||
val aggregatedContent: Content? = null,
|
||||
// The list of the eventIDs used to build the summary (might be out of sync if chunked received from message chunk)
|
||||
val sourceEvents: List<String>,
|
||||
val lastEditTs: Long = 0
|
||||
)
|
@ -1,7 +1,22 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
|
||||
data class EventAnnotationsSummary(
|
||||
var eventId: String,
|
||||
var reactionsSummary: List<ReactionAggregatedSummary>
|
||||
var reactionsSummary: List<ReactionAggregatedSummary>,
|
||||
var editSummary: EditAggregatedSummary?
|
||||
)
|
@ -5,7 +5,7 @@ import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class ReactionInfo(
|
||||
@Json(name = "rel_type") override val type: String,
|
||||
@Json(name = "rel_type") override val type: String?,
|
||||
@Json(name = "event_id") override val eventId: String,
|
||||
val key: String
|
||||
) : RelationContent
|
@ -1,6 +1,6 @@
|
||||
package im.vector.matrix.android.api.session.room.model.annotation
|
||||
|
||||
interface RelationContent {
|
||||
val type: String
|
||||
val eventId: String
|
||||
val type: String?
|
||||
val eventId: String?
|
||||
}
|
@ -1,8 +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.annotation
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class RelationDefaultContent(
|
||||
@Json(name = "rel_type") override val type: String,
|
||||
@Json(name = "event_id") override val eventId: String
|
||||
@Json(name = "rel_type") override val type: String?,
|
||||
@Json(name = "event_id") override val eventId: String?
|
||||
) : RelationContent
|
||||
|
@ -21,7 +21,7 @@ import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class FileInfo(
|
||||
@Json(name = "mimetype") val mimeType: String,
|
||||
@Json(name = "mimetype") val mimeType: String?,
|
||||
@Json(name = "size") val size: Long = 0,
|
||||
@Json(name = "thumbnail_info") val thumbnailInfo: ThumbnailInfo? = null,
|
||||
@Json(name = "thumbnail_url") val thumbnailUrl: String? = null
|
||||
|
@ -18,11 +18,15 @@ 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.annotation.RelationDefaultContent
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageAudioContent(
|
||||
@Json(name = "msgtype") override val type: String,
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "info") val info: AudioInfo? = null,
|
||||
@Json(name = "url") val url: String? = null
|
||||
@Json(name = "url") val url: String? = null,
|
||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||
@Json(name = "m.new_content") override val newContent: Content? = null
|
||||
) : MessageContent
|
@ -16,8 +16,13 @@
|
||||
|
||||
package im.vector.matrix.android.api.session.room.model.message
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.Content
|
||||
import im.vector.matrix.android.api.session.room.model.annotation.RelationDefaultContent
|
||||
|
||||
|
||||
interface MessageContent {
|
||||
val type: String
|
||||
val body: String
|
||||
val relatesTo: RelationDefaultContent?
|
||||
val newContent: Content?
|
||||
}
|
@ -18,9 +18,13 @@ 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.annotation.RelationDefaultContent
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageDefaultContent(
|
||||
@Json(name = "msgtype") override val type: String,
|
||||
@Json(name = "body") override val body: String
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||
@Json(name = "m.new_content") override val newContent: Content? = null
|
||||
) : MessageContent
|
@ -18,11 +18,15 @@ 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.annotation.RelationDefaultContent
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageEmoteContent(
|
||||
@Json(name = "msgtype") override val type: String,
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "format") val format: String? = null,
|
||||
@Json(name = "formatted_body") val formattedBody: String? = null
|
||||
@Json(name = "formatted_body") val formattedBody: String? = null,
|
||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||
@Json(name = "m.new_content") override val newContent: Content? = null
|
||||
) : MessageContent
|
@ -18,6 +18,8 @@ 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.annotation.RelationDefaultContent
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageFileContent(
|
||||
@ -25,5 +27,7 @@ data class MessageFileContent(
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "filename") val filename: String? = null,
|
||||
@Json(name = "info") val info: FileInfo? = null,
|
||||
@Json(name = "url") val url: String? = null
|
||||
@Json(name = "url") val url: String? = null,
|
||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||
@Json(name = "m.new_content") override val newContent: Content? = null
|
||||
) : MessageContent
|
@ -18,11 +18,15 @@ 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.annotation.RelationDefaultContent
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageImageContent(
|
||||
@Json(name = "msgtype") override val type: String,
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "info") val info: ImageInfo? = null,
|
||||
@Json(name = "url") val url: String? = null
|
||||
@Json(name = "url") val url: String? = null,
|
||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||
@Json(name = "m.new_content") override val newContent: Content? = null
|
||||
) : MessageContent
|
@ -18,11 +18,15 @@ 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.annotation.RelationDefaultContent
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageLocationContent(
|
||||
@Json(name = "msgtype") override val type: String,
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "geo_uri") val geoUri: String,
|
||||
@Json(name = "info") val info: LocationInfo? = null
|
||||
@Json(name = "info") val info: LocationInfo? = null,
|
||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||
@Json(name = "m.new_content") override val newContent: Content? = null
|
||||
) : MessageContent
|
@ -18,11 +18,15 @@ 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.annotation.RelationDefaultContent
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageNoticeContent(
|
||||
@Json(name = "msgtype") override val type: String,
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "format") val format: String? = null,
|
||||
@Json(name = "formatted_body") val formattedBody: String? = null
|
||||
@Json(name = "formatted_body") val formattedBody: String? = null,
|
||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||
@Json(name = "m.new_content") override val newContent: Content? = null
|
||||
) : MessageContent
|
@ -18,11 +18,15 @@ 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.annotation.RelationDefaultContent
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageTextContent(
|
||||
@Json(name = "msgtype") override val type: String,
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "format") val format: String? = null,
|
||||
@Json(name = "formatted_body") val formattedBody: String? = null
|
||||
@Json(name = "formatted_body") val formattedBody: String? = null,
|
||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||
@Json(name = "m.new_content") override val newContent: Content? = null
|
||||
) : MessageContent
|
@ -18,11 +18,15 @@ 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.annotation.RelationDefaultContent
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageVideoContent(
|
||||
@Json(name = "msgtype") override val type: String,
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "info") val info: VideoInfo? = null,
|
||||
@Json(name = "url") val url: String? = null
|
||||
@Json(name = "url") val url: String? = null,
|
||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||
@Json(name = "m.new_content") override val newContent: Content? = null
|
||||
) : MessageContent
|
@ -1,5 +1,6 @@
|
||||
package im.vector.matrix.android.internal.database.mapper
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary
|
||||
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
||||
import im.vector.matrix.android.api.session.room.model.ReactionAggregatedSummary
|
||||
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
|
||||
@ -16,6 +17,13 @@ internal object EventAnnotationsSummaryMapper {
|
||||
it.firstTimestamp,
|
||||
it.sourceEvents.toList()
|
||||
)
|
||||
},
|
||||
editSummary = annotationsSummary.editSummary?.let {
|
||||
EditAggregatedSummary(
|
||||
ContentMapper.map(it.aggregatedContent),
|
||||
it.sourceEvents.toList(),
|
||||
it.lastEditTs
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.internal.database.model
|
||||
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
|
||||
/**
|
||||
* Keep the latest state of edition of a message
|
||||
*/
|
||||
internal open class EditAggregatedSummaryEntity(
|
||||
var aggregatedContent: String? = null,
|
||||
// The list of the eventIDs used to build the summary (might be out of sync if chunked received from message chunk)
|
||||
var sourceEvents: RealmList<String> = RealmList(),
|
||||
var lastEditTs: Long = 0
|
||||
) : RealmObject() {
|
||||
|
||||
companion object
|
||||
|
||||
}
|
@ -24,7 +24,8 @@ internal open class EventAnnotationsSummaryEntity(
|
||||
@PrimaryKey
|
||||
var eventId: String = "",
|
||||
var roomId: String? = null,
|
||||
var reactionsSummary: RealmList<ReactionAggregatedSummaryEntity> = RealmList()
|
||||
var reactionsSummary: RealmList<ReactionAggregatedSummaryEntity> = RealmList(),
|
||||
var editSummary: EditAggregatedSummaryEntity? = null
|
||||
) : RealmObject() {
|
||||
|
||||
companion object
|
||||
|
@ -35,6 +35,7 @@ import io.realm.annotations.RealmModule
|
||||
SyncEntity::class,
|
||||
UserEntity::class,
|
||||
EventAnnotationsSummaryEntity::class,
|
||||
ReactionAggregatedSummaryEntity::class
|
||||
ReactionAggregatedSummaryEntity::class,
|
||||
EditAggregatedSummaryEntity::class
|
||||
])
|
||||
internal class SessionRealmModule
|
||||
|
@ -17,19 +17,7 @@
|
||||
package im.vector.matrix.android.internal.di
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.model.annotation.RelationContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageAudioContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageDefaultContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageEmoteContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageFileContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageLocationContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageNoticeContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageType
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.*
|
||||
import im.vector.matrix.android.internal.network.parsing.RuntimeJsonAdapterFactory
|
||||
import im.vector.matrix.android.internal.network.parsing.UriMoshiAdapter
|
||||
import im.vector.matrix.android.internal.session.sync.model.UserAccountData
|
||||
@ -41,17 +29,17 @@ object MoshiProvider {
|
||||
private val moshi: Moshi = Moshi.Builder()
|
||||
.add(UriMoshiAdapter())
|
||||
.add(RuntimeJsonAdapterFactory.of(UserAccountData::class.java, "type", UserAccountDataFallback::class.java)
|
||||
.registerSubtype(UserAccountDataDirectMessages::class.java, UserAccountData.TYPE_DIRECT_MESSAGES)
|
||||
.registerSubtype(UserAccountDataDirectMessages::class.java, UserAccountData.TYPE_DIRECT_MESSAGES)
|
||||
)
|
||||
.add(RuntimeJsonAdapterFactory.of(MessageContent::class.java, "msgtype", MessageDefaultContent::class.java)
|
||||
.registerSubtype(MessageTextContent::class.java, MessageType.MSGTYPE_TEXT)
|
||||
.registerSubtype(MessageNoticeContent::class.java, MessageType.MSGTYPE_NOTICE)
|
||||
.registerSubtype(MessageEmoteContent::class.java, MessageType.MSGTYPE_EMOTE)
|
||||
.registerSubtype(MessageAudioContent::class.java, MessageType.MSGTYPE_AUDIO)
|
||||
.registerSubtype(MessageImageContent::class.java, MessageType.MSGTYPE_IMAGE)
|
||||
.registerSubtype(MessageVideoContent::class.java, MessageType.MSGTYPE_VIDEO)
|
||||
.registerSubtype(MessageLocationContent::class.java, MessageType.MSGTYPE_LOCATION)
|
||||
.registerSubtype(MessageFileContent::class.java, MessageType.MSGTYPE_FILE)
|
||||
.registerSubtype(MessageTextContent::class.java, MessageType.MSGTYPE_TEXT)
|
||||
.registerSubtype(MessageNoticeContent::class.java, MessageType.MSGTYPE_NOTICE)
|
||||
.registerSubtype(MessageEmoteContent::class.java, MessageType.MSGTYPE_EMOTE)
|
||||
.registerSubtype(MessageAudioContent::class.java, MessageType.MSGTYPE_AUDIO)
|
||||
.registerSubtype(MessageImageContent::class.java, MessageType.MSGTYPE_IMAGE)
|
||||
.registerSubtype(MessageVideoContent::class.java, MessageType.MSGTYPE_VIDEO)
|
||||
.registerSubtype(MessageLocationContent::class.java, MessageType.MSGTYPE_LOCATION)
|
||||
.registerSubtype(MessageFileContent::class.java, MessageType.MSGTYPE_FILE)
|
||||
)
|
||||
.build()
|
||||
|
||||
|
@ -3,6 +3,9 @@ package im.vector.matrix.android.internal.session.room
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.events.model.*
|
||||
import im.vector.matrix.android.api.session.room.model.annotation.ReactionContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||
import im.vector.matrix.android.internal.database.mapper.ContentMapper
|
||||
import im.vector.matrix.android.internal.database.model.EditAggregatedSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.model.ReactionAggregatedSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.create
|
||||
@ -22,16 +25,66 @@ internal class EventRelationsAggregationUpdater(private val credentials: Credent
|
||||
handleReaction(event, roomId, realm)
|
||||
}
|
||||
EventType.MESSAGE -> {
|
||||
event.unsignedData?.relations?.annotations?.let {
|
||||
if (event.unsignedData?.relations?.annotations != null) {
|
||||
Timber.v("###REACTION Agreggation in room $roomId for event ${event.eventId}")
|
||||
handleInitialAggregatedRelations(event, roomId, it, realm)
|
||||
handleInitialAggregatedRelations(event, roomId, event.unsignedData.relations.annotations, realm)
|
||||
} else {
|
||||
val content: MessageContent? = event.content.toModel()
|
||||
if (content?.relatesTo?.type == RelationType.REPLACE) {
|
||||
Timber.v("###REPLACE in room $roomId for event ${event.eventId}")
|
||||
//A replace!
|
||||
handleReplace(event, content, roomId, realm)
|
||||
}
|
||||
}
|
||||
//TODO message edits
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleReplace(event: Event, content: MessageContent, roomId: String, realm: Realm) {
|
||||
val eventId = event.eventId ?: return
|
||||
val targetEventId = content.relatesTo?.eventId ?: return
|
||||
val newContent = content.newContent ?: return
|
||||
//ok, this is a replace
|
||||
var existing = EventAnnotationsSummaryEntity.where(realm, targetEventId).findFirst()
|
||||
if (existing == null) {
|
||||
Timber.v("###REPLACE creating no relation summary for ${targetEventId}")
|
||||
existing = EventAnnotationsSummaryEntity.create(realm, targetEventId)
|
||||
existing.roomId = roomId
|
||||
}
|
||||
|
||||
//we have it
|
||||
val existingSummary = existing.editSummary
|
||||
if (existingSummary == null) {
|
||||
Timber.v("###REPLACE no edit summary for ${targetEventId}, creating one")
|
||||
//create the edit summary
|
||||
val editSummary = realm.createObject(EditAggregatedSummaryEntity::class.java)
|
||||
editSummary.lastEditTs = event.originServerTs ?: System.currentTimeMillis()
|
||||
editSummary.aggregatedContent = ContentMapper.map(newContent)
|
||||
editSummary.sourceEvents.add(eventId)
|
||||
|
||||
existing.editSummary = editSummary
|
||||
} else {
|
||||
if (existingSummary.sourceEvents.contains(eventId)) {
|
||||
//ignore this event, we already know it (??)
|
||||
Timber.v("###REPLACE ignoring event for summary, it's known ${eventId}")
|
||||
return
|
||||
}
|
||||
//This message has already been edited
|
||||
if (event.originServerTs ?: 0 > existingSummary.lastEditTs ?: 0) {
|
||||
Timber.v("###REPLACE Computing aggregated edit summary")
|
||||
existingSummary.lastEditTs = event.originServerTs ?: System.currentTimeMillis()
|
||||
existingSummary.aggregatedContent = ContentMapper.map(newContent)
|
||||
existingSummary.sourceEvents.add(eventId)
|
||||
} else {
|
||||
//ignore this event for the summary
|
||||
Timber.v("###REPLACE ignoring event for summary, it's to old ${eventId}")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun handleInitialAggregatedRelations(event: Event, roomId: String, aggregation: AggregatedAnnotation, realm: Realm) {
|
||||
aggregation.chunk?.forEach {
|
||||
if (it.type == EventType.REACTION) {
|
||||
|
@ -16,12 +16,16 @@
|
||||
|
||||
package im.vector.riotredesign.features.home.room.detail.timeline.factory
|
||||
|
||||
import android.graphics.Color
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.view.View
|
||||
import androidx.annotation.ColorRes
|
||||
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.message.*
|
||||
import im.vector.matrix.android.api.session.room.send.SendState
|
||||
@ -73,6 +77,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
textColor = colorProvider.getColor(AvatarRenderer.getColorFromUserId(event.root.sender
|
||||
?: ""))
|
||||
}
|
||||
val hasBeenEdited = event.annotations?.editSummary != null
|
||||
val informationData = MessageInformationData(eventId = eventId,
|
||||
senderId = event.root.sender ?: "",
|
||||
sendState = event.sendState,
|
||||
@ -80,7 +85,8 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
avatarUrl = avatarUrl,
|
||||
memberName = formattedMemberName,
|
||||
showInformation = showInformation,
|
||||
orderedReactionList = event.annotations?.reactionsSummary?.map { Triple(it.key, it.count, it.addedByMe) }
|
||||
orderedReactionList = event.annotations?.reactionsSummary?.map { Triple(it.key, it.count, it.addedByMe) },
|
||||
hasBeenEdited = hasBeenEdited
|
||||
)
|
||||
|
||||
if (event.root.unsignedData?.redactedEvent != null) {
|
||||
@ -88,13 +94,21 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
return buildRedactedItem(informationData, callback)
|
||||
}
|
||||
|
||||
val messageContent: MessageContent = event.root.content.toModel() ?: return null
|
||||
val messageContent: MessageContent =
|
||||
event.annotations?.editSummary?.aggregatedContent?.toModel()
|
||||
?: event.root.content.toModel()
|
||||
?: return null
|
||||
|
||||
if (messageContent.relatesTo?.type == RelationType.REPLACE) {
|
||||
//TODO blank item or ignore??
|
||||
// ignore this event
|
||||
return BlankItem_()
|
||||
}
|
||||
// val all = event.root.toContent()
|
||||
// val ev = all.toModel<Event>()
|
||||
return when (messageContent) {
|
||||
is MessageEmoteContent -> buildEmoteMessageItem(messageContent, informationData, callback)
|
||||
is MessageTextContent -> buildTextMessageItem(event.sendState, messageContent, informationData, callback)
|
||||
is MessageTextContent -> buildTextMessageItem(event.sendState, messageContent, informationData, hasBeenEdited, callback)
|
||||
is MessageImageContent -> buildImageMessageItem(messageContent, informationData, callback)
|
||||
is MessageNoticeContent -> buildNoticeMessageItem(messageContent, informationData, callback)
|
||||
is MessageVideoContent -> buildVideoMessageItem(messageContent, informationData, callback)
|
||||
@ -254,6 +268,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
|
||||
private fun buildTextMessageItem(sendState: SendState, messageContent: MessageTextContent,
|
||||
informationData: MessageInformationData,
|
||||
hasBeenEdited: Boolean,
|
||||
callback: TimelineEventController.Callback?): MessageTextItem? {
|
||||
|
||||
val bodyToUse = messageContent.formattedBody?.let {
|
||||
@ -261,8 +276,20 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
} ?: messageContent.body
|
||||
|
||||
val linkifiedBody = linkifyBody(bodyToUse, callback)
|
||||
|
||||
return MessageTextItem_()
|
||||
.message(linkifiedBody)
|
||||
.apply {
|
||||
if (hasBeenEdited) {
|
||||
val spannable = SpannableStringBuilder()
|
||||
spannable.append(linkifiedBody)
|
||||
val editedSuffix = "(edited)"
|
||||
spannable.append(" ").append(editedSuffix)
|
||||
spannable.setSpan(ForegroundColorSpan(Color.LTGRAY), spannable.indexOf(editedSuffix), spannable.indexOf(editedSuffix) + editedSuffix.length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
|
||||
message(spannable)
|
||||
} else {
|
||||
message(linkifiedBody)
|
||||
}
|
||||
}
|
||||
.informationData(informationData)
|
||||
.reactionPillCallback(callback)
|
||||
.avatarClickListener(
|
||||
|
@ -129,7 +129,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
|
||||
}
|
||||
}
|
||||
|
||||
open fun shouldShowReactionAtBottom() : Boolean {
|
||||
open fun shouldShowReactionAtBottom(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.item
|
||||
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_timeline_event_blank_stub)
|
||||
abstract class BlankItem : VectorEpoxyModel<BlankItem.BlankHolder>() {
|
||||
class BlankHolder : VectorEpoxyHolder()
|
||||
}
|
@ -31,5 +31,6 @@ data class MessageInformationData(
|
||||
val memberName: CharSequence? = null,
|
||||
val showInformation: Boolean = true,
|
||||
/*List of reactions (emoji,count,isSelected)*/
|
||||
var orderedReactionList: List<Triple<String,Int,Boolean>>? = null
|
||||
var orderedReactionList: List<Triple<String,Int,Boolean>>? = null,
|
||||
var hasBeenEdited: Boolean = false
|
||||
) : Parcelable
|
@ -32,6 +32,8 @@
|
||||
android:id="@+id/messageContentBlankStub"
|
||||
style="@style/TimelineContentStubNoInfoLayoutParams"
|
||||
android:layout="@layout/item_timeline_event_blank_stub"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<ViewStub
|
||||
|
Loading…
Reference in New Issue
Block a user