diff --git a/CHANGES.md b/CHANGES.md index ef90baca8d..412d32a0a1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ Features: Improvements: - Add unread indent on room list (#485) + - Message Editing: Update notifications (#128) Other changes: - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt index 36ca360e08..73ef7b779a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt @@ -18,6 +18,7 @@ package im.vector.matrix.android.api.session.room.timeline import im.vector.matrix.android.api.session.events.model.Event 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.EventAnnotationsSummary import im.vector.matrix.android.api.session.room.model.ReadReceipt @@ -92,6 +93,13 @@ data class TimelineEvent( */ fun TimelineEvent.hasBeenEdited() = annotations?.editSummary != null +/** + * Get the eventId which was edited by this event if any + */ +fun TimelineEvent.getEditedEventId(): String? { + return root.getClearContent().toModel()?.relatesTo?.takeIf { it.type == RelationType.REPLACE }?.eventId +} + /** * Get last MessageContent, after a possible edition */ @@ -99,6 +107,20 @@ fun TimelineEvent.getLastMessageContent(): MessageContent? = annotations?.editSu ?: root.getClearContent().toModel() +/** + * Get last Message body, after a possible edition + */ +fun TimelineEvent.getLastMessageBody(): String? { + val lastMessageContent = getLastMessageContent() + + if (lastMessageContent != null) { + return lastMessageContent.newContent?.toModel()?.body ?: lastMessageContent.body + } + + return null +} + + fun TimelineEvent.getTextEditableContent(): String? { val originalContent = root.getClearContent().toModel() ?: return null val isReply = originalContent.isReply() || root.content.toModel()?.relatesTo?.inReplyTo?.eventId != null diff --git a/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt b/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt index 5ad064683c..dcb228cfbd 100755 --- a/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt +++ b/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt @@ -203,6 +203,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { val simpleNotifiableEvent = SimpleNotifiableEvent( session.myUserId, eventId, + null, true, //It's an issue in this case, all event will bing even if expected to be silent. title = getString(R.string.notification_unknown_new_event), description = "", diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/InviteNotifiableEvent.kt b/vector/src/main/java/im/vector/riotx/features/notifications/InviteNotifiableEvent.kt index d6f3655f4a..10add07a66 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/InviteNotifiableEvent.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/InviteNotifiableEvent.kt @@ -21,6 +21,7 @@ import androidx.core.app.NotificationCompat data class InviteNotifiableEvent( override var matrixID: String?, override val eventId: String, + override val editedEventId: String?, var roomId: String, override var noisy: Boolean, override val title: String, diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEvent.kt b/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEvent.kt index ea2e21ab02..bc9c711d67 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEvent.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEvent.kt @@ -20,6 +20,7 @@ import java.io.Serializable interface NotifiableEvent : Serializable { var matrixID: String? val eventId: String + val editedEventId: String? var noisy: Boolean val title: String val description: String? diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEventResolver.kt b/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEventResolver.kt index 6650bf0d0d..297e0b31e4 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEventResolver.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEventResolver.kt @@ -25,7 +25,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.RoomMember import im.vector.matrix.android.api.session.room.timeline.TimelineEvent -import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent +import im.vector.matrix.android.api.session.room.timeline.getEditedEventId +import im.vector.matrix.android.api.session.room.timeline.getLastMessageBody import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult import im.vector.riotx.BuildConfig import im.vector.riotx.R @@ -72,6 +73,7 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St return SimpleNotifiableEvent( session.myUserId, eventId = event.eventId!!, + editedEventId = timelineEvent.getEditedEventId(), noisy = false,//will be updated timestamp = event.originServerTs ?: System.currentTimeMillis(), description = bodyPreview, @@ -82,7 +84,6 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St } } - private fun resolveMessageEvent(event: TimelineEvent, session: Session): NotifiableEvent? { //The event only contains an eventId, and roomId (type is m.room.*) , we need to get the displayable content (names, avatar, text, etc...) @@ -93,14 +94,14 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St Timber.e("## Unable to resolve room for eventId [${event}]") // Ok room is not known in store, but we can still display something val body = - event.getLastMessageContent() - ?.body + event.getLastMessageBody() ?: stringProvider.getString(R.string.notification_unknown_new_event) val roomName = stringProvider.getString(R.string.notification_unknown_room_name) val senderDisplayName = event.senderName ?: event.root.senderId val notifiableEvent = NotifiableMessageEvent( eventId = event.root.eventId!!, + editedEventId = event.getEditedEventId(), timestamp = event.root.originServerTs ?: 0, noisy = false,//will be updated senderName = senderDisplayName, @@ -128,14 +129,14 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St } } - val body = event.getLastMessageContent() - ?.body + val body = event.getLastMessageBody() ?: stringProvider.getString(R.string.notification_unknown_new_event) val roomName = room.roomSummary()?.displayName ?: "" val senderDisplayName = event.senderName ?: event.root.senderId val notifiableEvent = NotifiableMessageEvent( eventId = event.root.eventId!!, + editedEventId = event.getEditedEventId(), timestamp = event.root.originServerTs ?: 0, noisy = false,//will be updated senderName = senderDisplayName, @@ -177,6 +178,7 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St return InviteNotifiableEvent( session.myUserId, eventId = event.eventId!!, + editedEventId = null, roomId = roomId, timestamp = event.originServerTs ?: 0, noisy = false,//will be set later diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableMessageEvent.kt b/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableMessageEvent.kt index 11c2d744f6..36af131130 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableMessageEvent.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableMessageEvent.kt @@ -20,6 +20,7 @@ import im.vector.matrix.android.api.session.events.model.EventType data class NotifiableMessageEvent( override val eventId: String, + override val editedEventId: String?, override var noisy: Boolean, override val timestamp: Long, var senderName: String?, diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationBroadcastReceiver.kt b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationBroadcastReceiver.kt index 638cf7d161..cb68d0101d 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationBroadcastReceiver.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationBroadcastReceiver.kt @@ -119,6 +119,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() { val notifiableMessageEvent = NotifiableMessageEvent( // Generate a Fake event id UUID.randomUUID().toString(), + null, false, System.currentTimeMillis(), session.getUser(session.myUserId)?.displayName diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationDrawerManager.kt b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationDrawerManager.kt index 551bbb808b..3ea4c970a0 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationDrawerManager.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationDrawerManager.kt @@ -101,7 +101,28 @@ class NotificationDrawerManager @Inject constructor(private val context: Context //keep the existing one, do not replace } } else { - eventList.add(notifiableEvent) + // Check if this is an edit + if (notifiableEvent.editedEventId != null) { + // This is an edition + val eventBeforeEdition = eventList.firstOrNull { + // Edition of an event + it.eventId == notifiableEvent.editedEventId + // or edition of an edition + || it.editedEventId == notifiableEvent.editedEventId + } + + if (eventBeforeEdition != null) { + // Replace the existing notification with the new content + eventList.remove(eventBeforeEdition) + + eventList.add(notifiableEvent) + } else { + // Ignore an edit of a not displayed event in the notification drawer + } + } else { + // Not an edit + eventList.add(notifiableEvent) + } } } } diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/SimpleNotifiableEvent.kt b/vector/src/main/java/im/vector/riotx/features/notifications/SimpleNotifiableEvent.kt index 8ec5ff9580..abd7b706bc 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/SimpleNotifiableEvent.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/SimpleNotifiableEvent.kt @@ -20,6 +20,7 @@ import androidx.core.app.NotificationCompat data class SimpleNotifiableEvent( override var matrixID: String?, override val eventId: String, + override val editedEventId: String?, override var noisy: Boolean, override val title: String, override val description: String,