using a process state of keep/removed rather than mapping to an ignored event id

- this state will be used to diff the currently rendered events against the new ones
This commit is contained in:
Adam Brown 2021-10-11 15:32:12 +01:00
parent b7b4c01bde
commit b27fb264fc
5 changed files with 56 additions and 43 deletions

View file

@ -17,6 +17,8 @@
package im.vector.app.features.notifications
import im.vector.app.features.invite.AutoAcceptInvites
import im.vector.app.features.notifications.Processed.KEEP
import im.vector.app.features.notifications.Processed.REMOVE
import javax.inject.Inject
class NotifiableEventProcessor @Inject constructor(
@ -24,16 +26,15 @@ class NotifiableEventProcessor @Inject constructor(
private val autoAcceptInvites: AutoAcceptInvites
) {
fun process(eventList: List<NotifiableEvent>, currentRoomId: String?): Map<String, NotifiableEvent?> {
return eventList.associateBy { it.eventId }
.mapValues { (_, value) ->
when (value) {
is InviteNotifiableEvent -> if (autoAcceptInvites.hideInvites) null else value
is NotifiableMessageEvent -> if (shouldIgnoreMessageEventInRoom(currentRoomId, value.roomId) || outdatedDetector.isMessageOutdated(value)) {
null
} else value
is SimpleNotifiableEvent -> value
}
fun process(eventList: List<NotifiableEvent>, currentRoomId: String?): List<Pair<Processed, NotifiableEvent>> {
return eventList.map {
when (it) {
is InviteNotifiableEvent -> if (autoAcceptInvites.hideInvites) REMOVE else KEEP
is NotifiableMessageEvent -> if (shouldIgnoreMessageEventInRoom(currentRoomId, it.roomId) || outdatedDetector.isMessageOutdated(it)) {
REMOVE
} else KEEP
is SimpleNotifiableEvent -> KEEP
} to it
}
}
@ -41,3 +42,10 @@ class NotifiableEventProcessor @Inject constructor(
return currentRoomId != null && roomId == currentRoomId
}
}
enum class Processed {
KEEP,
REMOVE
}
fun List<Pair<Processed, NotifiableEvent>>.onlyKeptEvents() = filter { it.first == KEEP }.map { it.second }

View file

@ -56,7 +56,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
}
private val eventList = loadEventInfo()
private var renderedEventsList = emptyMap<String, NotifiableEvent?>()
private var renderedEventsList = emptyList<Pair<Processed, NotifiableEvent>>()
private val avatarSize = context.resources.getDimensionPixelSize(R.dimen.profile_avatar_size)
private var currentRoomId: String? = null
@ -236,10 +236,12 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
val eventsToRender = synchronized(eventList) {
notifiableEventProcessor.process(eventList, currentRoomId).also {
eventList.clear()
eventList.addAll(it.values.filterNotNull())
eventList.addAll(it.onlyKeptEvents())
}
}
if (renderedEventsList == eventsToRender) {
Timber.d("Skipping notification update due to event list not changing")
} else {

View file

@ -40,14 +40,14 @@ class NotificationFactory @Inject constructor(
private fun NotifiableMessageEvent.canNotBeDisplayed() = isRedacted
fun Map<String, InviteNotifiableEvent?>.toNotifications(myUserId: String): List<OneShotNotification> {
return map { (roomId, event) ->
when (event) {
null -> OneShotNotification.Removed(key = roomId)
else -> OneShotNotification.Append(
fun List<Pair<Processed, InviteNotifiableEvent>>.toNotifications(myUserId: String): List<OneShotNotification> {
return map { (processed, event) ->
when (processed) {
Processed.REMOVE -> OneShotNotification.Removed(key = event.roomId)
Processed.KEEP -> OneShotNotification.Append(
notificationUtils.buildRoomInvitationNotification(event, myUserId),
OneShotNotification.Append.Meta(
key = roomId,
key = event.roomId,
summaryLine = event.description,
isNoisy = event.noisy,
timestamp = event.timestamp
@ -58,14 +58,14 @@ class NotificationFactory @Inject constructor(
}
@JvmName("toNotificationsSimpleNotifiableEvent")
fun Map<String, SimpleNotifiableEvent?>.toNotifications(myUserId: String): List<OneShotNotification> {
return map { (eventId, event) ->
when (event) {
null -> OneShotNotification.Removed(key = eventId)
else -> OneShotNotification.Append(
fun List<Pair<Processed, SimpleNotifiableEvent>>.toNotifications(myUserId: String): List<OneShotNotification> {
return map { (processed, event) ->
when (processed) {
Processed.REMOVE -> OneShotNotification.Removed(key = event.eventId)
Processed.KEEP -> OneShotNotification.Append(
notificationUtils.buildSimpleEventNotification(event, myUserId),
OneShotNotification.Append.Meta(
key = eventId,
key = event.eventId,
summaryLine = event.description,
isNoisy = event.noisy,
timestamp = event.timestamp

View file

@ -34,7 +34,7 @@ class NotificationRenderer @Inject constructor(private val notificationDisplayer
myUserDisplayName: String,
myUserAvatarUrl: String?,
useCompleteNotificationFormat: Boolean,
eventsToProcess: Map<String, NotifiableEvent?>) {
eventsToProcess: List<Pair<Processed, NotifiableEvent>>) {
val (roomEvents, simpleEvents, invitationEvents) = eventsToProcess.groupByType()
with(notificationFactory) {
val roomNotifications = roomEvents.toNotifications(myUserDisplayName, myUserAvatarUrl)
@ -108,25 +108,28 @@ class NotificationRenderer @Inject constructor(private val notificationDisplayer
}
}
private fun Map<String, NotifiableEvent?>.groupByType(): GroupedNotificationEvents {
private fun List<Pair<Processed, NotifiableEvent>>.groupByType(): GroupedNotificationEvents {
val roomIdToEventMap: MutableMap<String, MutableList<NotifiableMessageEvent>> = LinkedHashMap()
val simpleEvents: MutableMap<String, SimpleNotifiableEvent?> = LinkedHashMap()
val invitationEvents: MutableMap<String, InviteNotifiableEvent?> = LinkedHashMap()
forEach { (_, value) ->
when (value) {
is InviteNotifiableEvent -> invitationEvents[value.roomId]
val simpleEvents: MutableList<Pair<Processed, SimpleNotifiableEvent>> = ArrayList()
val invitationEvents: MutableList<Pair<Processed, InviteNotifiableEvent>> = ArrayList()
forEach {
when (val event = it.second) {
is InviteNotifiableEvent -> invitationEvents.add(it.asPair())
is NotifiableMessageEvent -> {
val roomEvents = roomIdToEventMap.getOrPut(value.roomId) { ArrayList() }
roomEvents.add(value)
val roomEvents = roomIdToEventMap.getOrPut(event.roomId) { ArrayList() }
roomEvents.add(event)
}
is SimpleNotifiableEvent -> simpleEvents[value.eventId] = value
is SimpleNotifiableEvent -> simpleEvents.add(it.asPair())
}
}
return GroupedNotificationEvents(roomIdToEventMap, simpleEvents, invitationEvents)
}
@Suppress("UNCHECKED_CAST")
private fun <T: NotifiableEvent> Pair<Processed, *>.asPair(): Pair<Processed, T> = this as Pair<Processed, T>
data class GroupedNotificationEvents(
val roomEvents: Map<String, List<NotifiableMessageEvent>>,
val simpleEvents: Map<String, SimpleNotifiableEvent?>,
val invitationEvents: Map<String, InviteNotifiableEvent?>
val simpleEvents: List<Pair<Processed, SimpleNotifiableEvent>>,
val invitationEvents: List<Pair<Processed, InviteNotifiableEvent>>
)

View file

@ -37,7 +37,7 @@ class NotifiableEventProcessorTest {
aSimpleNotifiableEvent(eventId = "event-2")
)
val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM)
val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM, renderedEventsList = renderedEventsList)
result shouldBeEqualTo aProcessedNotificationEvents(
simpleEvents = mapOf(
@ -56,7 +56,7 @@ class NotifiableEventProcessorTest {
anInviteNotifiableEvent(roomId = "room-2")
)
val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM)
val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM, renderedEventsList = renderedEventsList)
result shouldBeEqualTo aProcessedNotificationEvents(
invitationEvents = mapOf(
@ -75,7 +75,7 @@ class NotifiableEventProcessorTest {
anInviteNotifiableEvent(roomId = "room-2")
)
val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM)
val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM, renderedEventsList = renderedEventsList)
result shouldBeEqualTo aProcessedNotificationEvents(
invitationEvents = mapOf(
@ -91,7 +91,7 @@ class NotifiableEventProcessorTest {
val (events) = createEventsList(aNotifiableMessageEvent(eventId = "event-1", roomId = "room-1"))
outdatedDetector.givenEventIsOutOfDate(events[0])
val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM)
val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM, renderedEventsList = renderedEventsList)
result shouldBeEqualTo aProcessedNotificationEvents(
roomEvents = mapOf(
@ -106,7 +106,7 @@ class NotifiableEventProcessorTest {
val (events, originalEvents) = createEventsList(aNotifiableMessageEvent(eventId = "event-1", roomId = "room-1"))
outdatedDetector.givenEventIsInDate(events[0])
val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM)
val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM, renderedEventsList = renderedEventsList)
result shouldBeEqualTo aProcessedNotificationEvents(
roomEvents = mapOf(
@ -120,7 +120,7 @@ class NotifiableEventProcessorTest {
fun `given viewing the same room as message event when processing then removes message`() {
val (events) = createEventsList(aNotifiableMessageEvent(eventId = "event-1", roomId = "room-1"))
val result = eventProcessor.process(events, currentRoomId = "room-1")
val result = eventProcessor.process(events, currentRoomId = "room-1", renderedEventsList = renderedEventsList)
result shouldBeEqualTo aProcessedNotificationEvents(
roomEvents = mapOf(