From 40a68c3e9f30b84b31eaba309df43f2aafd739ef Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 19 Jul 2019 16:13:35 +0200 Subject: [PATCH 1/3] Show pending edits by fading the event body #193 + Fix issues with edits local echo management in aggregation --- .../room/EventRelationsAggregationTask.kt | 48 ++++++++++++------- .../detail/timeline/item/AbsMessageItem.kt | 5 +- .../timeline/item/MessageInformationData.kt | 3 +- .../util/MessageInformationDataFactory.kt | 3 +- 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt index 867ca287..2e1a4273 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt @@ -83,21 +83,21 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( if (event.unsignedData?.relations?.annotations != null) { Timber.v("###REACTION Agreggation in room $roomId for event ${event.eventId}") 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(realm, event, content, roomId, isLocalEcho) + + EventAnnotationsSummaryEntity.where(realm, event.eventId + ?: "").findFirst()?.let { + TimelineEventEntity.where(realm, eventId = event.eventId + ?: "").findFirst()?.let { tet -> + tet.annotations = it + } } } - EventAnnotationsSummaryEntity.where(realm, event.eventId - ?: "").findFirst()?.let { - TimelineEventEntity.where(realm, eventId = event.eventId - ?: "").findFirst()?.let { tet -> - tet.annotations = it - } + 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(realm, event, content, roomId, isLocalEcho) } @@ -178,11 +178,12 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( Timber.v("###REPLACE new edit summary for ${targetEventId}, creating one (localEcho:$isLocalEcho)") //create the edit summary val editSummary = realm.createObject(EditAggregatedSummaryEntity::class.java) - editSummary.lastEditTs = event.originServerTs ?: System.currentTimeMillis() editSummary.aggregatedContent = ContentMapper.map(newContent) if (isLocalEcho) { + editSummary.lastEditTs = 0 editSummary.sourceLocalEchoEvents.add(eventId) } else { + editSummary.lastEditTs = event.originServerTs ?: 0 editSummary.sourceEvents.add(eventId) } @@ -200,13 +201,26 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( Timber.v("###REPLACE Receiving remote echo of edit (edit already done)") existingSummary.sourceLocalEchoEvents.remove(txId) existingSummary.sourceEvents.add(event.eventId) - } else if (event.originServerTs ?: 0 > existingSummary.lastEditTs) { + } else if ( + isLocalEcho // do not rely on ts for local echo, take it + || event.originServerTs ?: 0 >= existingSummary.lastEditTs + ) { Timber.v("###REPLACE Computing aggregated edit summary (isLocalEcho:$isLocalEcho)") - existingSummary.lastEditTs = event.originServerTs ?: System.currentTimeMillis() + if (!isLocalEcho) { + //Do not take local echo originServerTs here, could mess up ordering (keep old ts) + existingSummary.lastEditTs = event.originServerTs ?: System.currentTimeMillis() + } existingSummary.aggregatedContent = ContentMapper.map(newContent) - existingSummary.sourceEvents.add(eventId) + if (isLocalEcho) { + existingSummary.sourceLocalEchoEvents.add(eventId) + } else { + existingSummary.sourceEvents.add(eventId) + } } else { - //ignore this event for the summary + //ignore this event for the summary (back paginate) + if (!isLocalEcho) { + existingSummary.sourceEvents.add(eventId) + } Timber.v("###REPLACE ignoring event for summary, it's to old $eventId") } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt index 88697db4..6e4f4994 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt @@ -29,6 +29,7 @@ import androidx.core.view.children import androidx.core.view.isGone import androidx.core.view.isVisible import com.airbnb.epoxy.EpoxyAttribute +import im.vector.matrix.android.api.session.room.send.SendState import im.vector.riotx.R import im.vector.riotx.core.resources.ColorProvider import im.vector.riotx.core.utils.DebouncedClickListener @@ -163,7 +164,9 @@ abstract class AbsMessageItem : BaseEventItem() { protected fun renderSendState(root: View, textView: TextView?) { root.isClickable = informationData.sendState.isSent() - textView?.setTextColor(colorProvider.getMessageTextColor(informationData.sendState)) + val state = SendState.UNSENT.takeIf { informationData.hasPendingEdits } + ?: informationData.sendState + textView?.setTextColor(colorProvider.getMessageTextColor(state)) } abstract class Holder(@IdRes stubId: Int) : BaseHolder(stubId) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageInformationData.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageInformationData.kt index 5f49fdc3..092f8ce7 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageInformationData.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageInformationData.kt @@ -31,7 +31,8 @@ data class MessageInformationData( val showInformation: Boolean = true, /*List of reactions (emoji,count,isSelected)*/ var orderedReactionList: List? = null, - var hasBeenEdited: Boolean = false + var hasBeenEdited: Boolean = false, + var hasPendingEdits: Boolean = false ) : Parcelable diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/util/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/util/MessageInformationDataFactory.kt index d17c8de6..eb13ac7b 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/util/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/util/MessageInformationDataFactory.kt @@ -74,7 +74,8 @@ class MessageInformationDataFactory @Inject constructor(private val timelineDate ?.map { ReactionInfoData(it.key, it.count, it.addedByMe, it.localEchoEvents.isEmpty()) }, - hasBeenEdited = hasBeenEdited + hasBeenEdited = hasBeenEdited, + hasPendingEdits = event.annotations?.editSummary?.localEchos?.any() ?: false ) } } \ No newline at end of file From 36af8a6a9f1cb2b90c2aeb75312085deef9a4cab Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 19 Jul 2019 16:13:55 +0200 Subject: [PATCH 2/3] Lab / show replace in timeline when show hidden event selected --- .../timeline/factory/MessageItemFactory.kt | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MessageItemFactory.kt index c330b85d..b2e8216b 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -41,11 +41,13 @@ import im.vector.riotx.core.epoxy.VectorEpoxyModel import im.vector.riotx.core.linkify.VectorLinkify import im.vector.riotx.core.resources.ColorProvider import im.vector.riotx.core.resources.StringProvider +import im.vector.riotx.core.resources.UserPreferencesProvider import im.vector.riotx.core.utils.DebouncedClickListener import im.vector.riotx.features.home.AvatarRenderer import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController import im.vector.riotx.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider +import im.vector.riotx.features.home.room.detail.timeline.helper.senderAvatar import im.vector.riotx.features.home.room.detail.timeline.item.* import im.vector.riotx.features.home.room.detail.timeline.util.MessageInformationDataFactory import im.vector.riotx.features.html.EventHtmlRenderer @@ -63,7 +65,8 @@ class MessageItemFactory @Inject constructor( private val emojiCompatFontProvider: EmojiCompatFontProvider, private val imageContentRenderer: ImageContentRenderer, private val messageInformationDataFactory: MessageInformationDataFactory, - private val contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder) { + private val contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder, + private val userPreferencesProvider: UserPreferencesProvider) { fun create(event: TimelineEvent, @@ -89,7 +92,26 @@ class MessageItemFactory @Inject constructor( || event.isEncrypted() && event.root.content.toModel()?.relatesTo?.type == RelationType.REPLACE ) { // ignore replace event, the targeted id is already edited - return BlankItem_() + if (userPreferencesProvider.shouldShowHiddenEvents()) { + //These are just for debug to display hidden event, they should be filtered out in normal mode + val informationData = MessageInformationData( + eventId = event.root.eventId ?: "?", + senderId = event.root.senderId ?: "", + sendState = event.sendState, + time = "", + avatarUrl = event.senderAvatar(), + memberName = "", + showInformation = false + ) + return NoticeItem_() + .avatarRenderer(avatarRenderer) + .informationData(informationData) + .noticeText("{ \"type\": ${event.root.getClearType()} }") + .highlighted(highlight) + .baseCallback(callback) + } else { + return BlankItem_() + } } // val all = event.root.toContent() // val ev = all.toModel() From c58328f94e34d7833c6e79ceb5f54a6d185b2ea3 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 22 Jul 2019 23:34:40 +0200 Subject: [PATCH 3/3] cleaning / review --- CHANGES.md | 2 +- .../home/room/detail/timeline/item/AbsMessageItem.kt | 3 +-- .../room/detail/timeline/item/MessageInformationData.kt | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index cc5689d4..909b8512 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,7 +5,7 @@ Features: - Improvements: - - + - UI for pending edits (#193) Other changes: - diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt index 6e4f4994..6f7f5b86 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt @@ -164,8 +164,7 @@ abstract class AbsMessageItem : BaseEventItem() { protected fun renderSendState(root: View, textView: TextView?) { root.isClickable = informationData.sendState.isSent() - val state = SendState.UNSENT.takeIf { informationData.hasPendingEdits } - ?: informationData.sendState + val state = if (informationData.hasPendingEdits) SendState.UNSENT else informationData.sendState textView?.setTextColor(colorProvider.getMessageTextColor(state)) } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageInformationData.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageInformationData.kt index 092f8ce7..31b92c0e 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageInformationData.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageInformationData.kt @@ -30,9 +30,9 @@ data class MessageInformationData( val memberName: CharSequence? = null, val showInformation: Boolean = true, /*List of reactions (emoji,count,isSelected)*/ - var orderedReactionList: List? = null, - var hasBeenEdited: Boolean = false, - var hasPendingEdits: Boolean = false + val orderedReactionList: List? = null, + val hasBeenEdited: Boolean = false, + val hasPendingEdits: Boolean = false ) : Parcelable