From 8cb884f10ea6ae5506f885f697bdfc3f25d93264 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 20 May 2019 18:52:48 +0200 Subject: [PATCH] Support message edition --- .../room/model/EditAggregatedSummary.kt | 25 ++++++++ .../room/model/EventAnnotationsSummary.kt | 19 +++++- .../room/model/annotation/ReactionInfo.kt | 2 +- .../room/model/annotation/RelationContent.kt | 4 +- .../annotation/RelationDefaultContent.kt | 21 ++++++- .../session/room/model/message/FileInfo.kt | 2 +- .../room/model/message/MessageAudioContent.kt | 6 +- .../room/model/message/MessageContent.kt | 5 ++ .../model/message/MessageDefaultContent.kt | 6 +- .../room/model/message/MessageEmoteContent.kt | 6 +- .../room/model/message/MessageFileContent.kt | 6 +- .../room/model/message/MessageImageContent.kt | 6 +- .../model/message/MessageLocationContent.kt | 6 +- .../model/message/MessageNoticeContent.kt | 6 +- .../room/model/message/MessageTextContent.kt | 6 +- .../room/model/message/MessageVideoContent.kt | 6 +- .../mapper/EventAnnotationsSummaryMapper.kt | 8 +++ .../model/EditAggregatedSummaryEntity.kt | 33 +++++++++++ .../model/EventAnnotationsSummaryEntity.kt | 3 +- .../database/model/SessionRealmModule.kt | 3 +- .../android/internal/di/MoshiProvider.kt | 32 ++++------ .../room/EventRelationsAggregationUpdater.kt | 59 ++++++++++++++++++- .../timeline/factory/MessageItemFactory.kt | 35 +++++++++-- .../detail/timeline/item/AbsMessageItem.kt | 2 +- .../room/detail/timeline/item/BlankItem.kt | 27 +++++++++ .../timeline/item/MessageInformationData.kt | 3 +- .../item_timeline_event_base_noinfo.xml | 2 + 27 files changed, 289 insertions(+), 50 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EditAggregatedSummary.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EditAggregatedSummaryEntity.kt create mode 100644 vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/BlankItem.kt diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EditAggregatedSummary.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EditAggregatedSummary.kt new file mode 100644 index 00000000..636343a5 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EditAggregatedSummary.kt @@ -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, + val lastEditTs: Long = 0 +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EventAnnotationsSummary.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EventAnnotationsSummary.kt index 15008439..18899f87 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EventAnnotationsSummary.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EventAnnotationsSummary.kt @@ -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 + var reactionsSummary: List, + var editSummary: EditAggregatedSummary? ) \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/annotation/ReactionInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/annotation/ReactionInfo.kt index 14444508..bf573744 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/annotation/ReactionInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/annotation/ReactionInfo.kt @@ -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 \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/annotation/RelationContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/annotation/RelationContent.kt index ccdd10a0..d9e23b30 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/annotation/RelationContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/annotation/RelationContent.kt @@ -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? } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/annotation/RelationDefaultContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/annotation/RelationDefaultContent.kt index 1d00b1a4..7137e86a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/annotation/RelationDefaultContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/annotation/RelationDefaultContent.kt @@ -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 diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/FileInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/FileInfo.kt index 2a115a58..16dc4d23 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/FileInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/FileInfo.kt @@ -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 diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageAudioContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageAudioContent.kt index ffae8eef..f1df2b58 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageAudioContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageAudioContent.kt @@ -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 \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageContent.kt index 1d6880b0..efc9af06 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageContent.kt @@ -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? } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageDefaultContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageDefaultContent.kt index a924efe4..4fb96a83 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageDefaultContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageDefaultContent.kt @@ -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 \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageEmoteContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageEmoteContent.kt index bae9c96f..8053fde4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageEmoteContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageEmoteContent.kt @@ -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 \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageFileContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageFileContent.kt index 505aee7a..57039d64 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageFileContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageFileContent.kt @@ -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 \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageImageContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageImageContent.kt index a3e2f661..394b9879 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageImageContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageImageContent.kt @@ -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 \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageLocationContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageLocationContent.kt index b17bfae1..d3a81a93 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageLocationContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageLocationContent.kt @@ -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 \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageNoticeContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageNoticeContent.kt index 4db1f4a0..53adaf9b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageNoticeContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageNoticeContent.kt @@ -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 \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageTextContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageTextContent.kt index 084b5dde..7942c259 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageTextContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageTextContent.kt @@ -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 \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageVideoContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageVideoContent.kt index 319a9493..0ca7def1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageVideoContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageVideoContent.kt @@ -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 \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventAnnotationsSummaryMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventAnnotationsSummaryMapper.kt index 38388950..2d1a7da1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventAnnotationsSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventAnnotationsSummaryMapper.kt @@ -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 + ) } ) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EditAggregatedSummaryEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EditAggregatedSummaryEntity.kt new file mode 100644 index 00000000..4b2a43e8 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EditAggregatedSummaryEntity.kt @@ -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 = RealmList(), + var lastEditTs: Long = 0 +) : RealmObject() { + + companion object + +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventAnnotationsSummaryEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventAnnotationsSummaryEntity.kt index bd4c2077..4c6b26f0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventAnnotationsSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventAnnotationsSummaryEntity.kt @@ -24,7 +24,8 @@ internal open class EventAnnotationsSummaryEntity( @PrimaryKey var eventId: String = "", var roomId: String? = null, - var reactionsSummary: RealmList = RealmList() + var reactionsSummary: RealmList = RealmList(), + var editSummary: EditAggregatedSummaryEntity? = null ) : RealmObject() { companion object diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt index dc3ad001..20ba8d44 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt @@ -35,6 +35,7 @@ import io.realm.annotations.RealmModule SyncEntity::class, UserEntity::class, EventAnnotationsSummaryEntity::class, - ReactionAggregatedSummaryEntity::class + ReactionAggregatedSummaryEntity::class, + EditAggregatedSummaryEntity::class ]) internal class SessionRealmModule diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt index 45eb7831..43d1c488 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt @@ -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() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt index 85e7245d..3ec43a44 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt @@ -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) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt index b4374c0c..03a4f768 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -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() 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( diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/AbsMessageItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/AbsMessageItem.kt index 4e219fad..d560424d 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/AbsMessageItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/AbsMessageItem.kt @@ -129,7 +129,7 @@ abstract class AbsMessageItem : BaseEventItem() { } } - open fun shouldShowReactionAtBottom() : Boolean { + open fun shouldShowReactionAtBottom(): Boolean { return true } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/BlankItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/BlankItem.kt new file mode 100644 index 00000000..39ab2c42 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/BlankItem.kt @@ -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() { + class BlankHolder : VectorEpoxyHolder() +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageInformationData.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageInformationData.kt index b0d25f9b..5cdd1f9c 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageInformationData.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageInformationData.kt @@ -31,5 +31,6 @@ data class MessageInformationData( val memberName: CharSequence? = null, val showInformation: Boolean = true, /*List of reactions (emoji,count,isSelected)*/ - var orderedReactionList: List>? = null + var orderedReactionList: List>? = null, + var hasBeenEdited: Boolean = false ) : Parcelable \ No newline at end of file diff --git a/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml b/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml index 9504e205..07b43f7b 100644 --- a/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml +++ b/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml @@ -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" />