NotificationDataFactory: improve API

This commit is contained in:
Benoit Marty 2025-10-26 08:49:48 +01:00 committed by Benoit Marty
parent 031ca4f333
commit b0e5e6cc61
4 changed files with 45 additions and 64 deletions

View file

@ -28,30 +28,26 @@ import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiab
import io.element.android.services.toolbox.api.strings.StringProvider import io.element.android.services.toolbox.api.strings.StringProvider
interface NotificationDataFactory { interface NotificationDataFactory {
suspend fun toNotifications( suspend fun List<NotifiableMessageEvent>.toNotifications(
messages: List<NotifiableMessageEvent>,
imageLoader: ImageLoader, imageLoader: ImageLoader,
notificationAccountParams: NotificationAccountParams, notificationAccountParams: NotificationAccountParams,
): List<RoomNotification> ): List<RoomNotification>
@JvmName("toNotificationInvites") @JvmName("toNotificationInvites")
@Suppress("INAPPLICABLE_JVM_NAME") @Suppress("INAPPLICABLE_JVM_NAME")
fun toNotifications( fun List<InviteNotifiableEvent>.toNotifications(
invites: List<InviteNotifiableEvent>,
notificationAccountParams: NotificationAccountParams, notificationAccountParams: NotificationAccountParams,
): List<OneShotNotification> ): List<OneShotNotification>
@JvmName("toNotificationSimpleEvents") @JvmName("toNotificationSimpleEvents")
@Suppress("INAPPLICABLE_JVM_NAME") @Suppress("INAPPLICABLE_JVM_NAME")
fun toNotifications( fun List<SimpleNotifiableEvent>.toNotifications(
simpleEvents: List<SimpleNotifiableEvent>,
notificationAccountParams: NotificationAccountParams, notificationAccountParams: NotificationAccountParams,
): List<OneShotNotification> ): List<OneShotNotification>
@JvmName("toNotificationFallbackEvents") @JvmName("toNotificationFallbackEvents")
@Suppress("INAPPLICABLE_JVM_NAME") @Suppress("INAPPLICABLE_JVM_NAME")
fun toNotifications( fun List<FallbackNotifiableEvent>.toNotifications(
fallback: List<FallbackNotifiableEvent>,
notificationAccountParams: NotificationAccountParams, notificationAccountParams: NotificationAccountParams,
): List<OneShotNotification> ): List<OneShotNotification>
@ -72,12 +68,11 @@ class DefaultNotificationDataFactory(
private val activeNotificationsProvider: ActiveNotificationsProvider, private val activeNotificationsProvider: ActiveNotificationsProvider,
private val stringProvider: StringProvider, private val stringProvider: StringProvider,
) : NotificationDataFactory { ) : NotificationDataFactory {
override suspend fun toNotifications( override suspend fun List<NotifiableMessageEvent>.toNotifications(
messages: List<NotifiableMessageEvent>,
imageLoader: ImageLoader, imageLoader: ImageLoader,
notificationAccountParams: NotificationAccountParams, notificationAccountParams: NotificationAccountParams,
): List<RoomNotification> { ): List<RoomNotification> {
val messagesToDisplay = messages.filterNot { it.canNotBeDisplayed() } val messagesToDisplay = filterNot { it.canNotBeDisplayed() }
.groupBy { it.roomId } .groupBy { it.roomId }
return messagesToDisplay.flatMap { (roomId, events) -> return messagesToDisplay.flatMap { (roomId, events) ->
val roomName = events.lastOrNull()?.roomName ?: roomId.value val roomName = events.lastOrNull()?.roomName ?: roomId.value
@ -114,11 +109,10 @@ class DefaultNotificationDataFactory(
@JvmName("toNotificationInvites") @JvmName("toNotificationInvites")
@Suppress("INAPPLICABLE_JVM_NAME") @Suppress("INAPPLICABLE_JVM_NAME")
override fun toNotifications( override fun List<InviteNotifiableEvent>.toNotifications(
invites: List<InviteNotifiableEvent>,
notificationAccountParams: NotificationAccountParams, notificationAccountParams: NotificationAccountParams,
): List<OneShotNotification> { ): List<OneShotNotification> {
return invites.map { event -> return map { event ->
OneShotNotification( OneShotNotification(
key = event.roomId.value, key = event.roomId.value,
notification = notificationCreator.createRoomInvitationNotification(notificationAccountParams, event), notification = notificationCreator.createRoomInvitationNotification(notificationAccountParams, event),
@ -131,11 +125,10 @@ class DefaultNotificationDataFactory(
@JvmName("toNotificationSimpleEvents") @JvmName("toNotificationSimpleEvents")
@Suppress("INAPPLICABLE_JVM_NAME") @Suppress("INAPPLICABLE_JVM_NAME")
override fun toNotifications( override fun List<SimpleNotifiableEvent>.toNotifications(
simpleEvents: List<SimpleNotifiableEvent>,
notificationAccountParams: NotificationAccountParams, notificationAccountParams: NotificationAccountParams,
): List<OneShotNotification> { ): List<OneShotNotification> {
return simpleEvents.map { event -> return map { event ->
OneShotNotification( OneShotNotification(
key = event.eventId.value, key = event.eventId.value,
notification = notificationCreator.createSimpleEventNotification(notificationAccountParams, event), notification = notificationCreator.createSimpleEventNotification(notificationAccountParams, event),
@ -148,11 +141,10 @@ class DefaultNotificationDataFactory(
@JvmName("toNotificationFallbackEvents") @JvmName("toNotificationFallbackEvents")
@Suppress("INAPPLICABLE_JVM_NAME") @Suppress("INAPPLICABLE_JVM_NAME")
override fun toNotifications( override fun List<FallbackNotifiableEvent>.toNotifications(
fallback: List<FallbackNotifiableEvent>,
notificationAccountParams: NotificationAccountParams, notificationAccountParams: NotificationAccountParams,
): List<OneShotNotification> { ): List<OneShotNotification> {
return fallback.map { event -> return map { event ->
OneShotNotification( OneShotNotification(
key = event.eventId.value, key = event.eventId.value,
notification = notificationCreator.createFallbackNotification(notificationAccountParams, event), notification = notificationCreator.createFallbackNotification(notificationAccountParams, event),

View file

@ -51,10 +51,18 @@ class NotificationRenderer(
showSessionId = numberOfAccounts > 1, showSessionId = numberOfAccounts > 1,
) )
val groupedEvents = eventsToProcess.groupByType() val groupedEvents = eventsToProcess.groupByType()
val roomNotifications = notificationDataFactory.toNotifications(groupedEvents.roomEvents, imageLoader, notificationAccountParams) val roomNotifications = with(notificationDataFactory) {
val invitationNotifications = notificationDataFactory.toNotifications(groupedEvents.invitationEvents, notificationAccountParams) groupedEvents.roomEvents.toNotifications(imageLoader, notificationAccountParams)
val simpleNotifications = notificationDataFactory.toNotifications(groupedEvents.simpleEvents, notificationAccountParams) }
val fallbackNotifications = notificationDataFactory.toNotifications(groupedEvents.fallbackEvents, notificationAccountParams) val invitationNotifications = with(notificationDataFactory) {
groupedEvents.invitationEvents.toNotifications(notificationAccountParams)
}
val simpleNotifications = with(notificationDataFactory) {
groupedEvents.simpleEvents.toNotifications(notificationAccountParams)
}
val fallbackNotifications = with(notificationDataFactory) {
groupedEvents.fallbackEvents.toNotifications(notificationAccountParams)
}
val summaryNotification = notificationDataFactory.createSummaryNotification( val summaryNotification = notificationDataFactory.createSummaryNotification(
roomNotifications = roomNotifications, roomNotifications = roomNotifications,
invitationNotifications = invitationNotifications, invitationNotifications = invitationNotifications,

View file

@ -55,10 +55,7 @@ class NotificationDataFactoryTest {
aNotificationAccountParams(), aNotificationAccountParams(),
AN_INVITATION_EVENT, AN_INVITATION_EVENT,
) )
val roomInvitation = listOf(AN_INVITATION_EVENT) val result = listOf(AN_INVITATION_EVENT).toNotifications(aNotificationAccountParams())
val result = toNotifications(roomInvitation, aNotificationAccountParams())
assertThat(result).isEqualTo( assertThat(result).isEqualTo(
listOf( listOf(
OneShotNotification( OneShotNotification(
@ -78,19 +75,14 @@ class NotificationDataFactoryTest {
aNotificationAccountParams(), aNotificationAccountParams(),
AN_INVITATION_EVENT, AN_INVITATION_EVENT,
) )
val roomInvitation = listOf(A_SIMPLE_EVENT) val result = listOf(A_SIMPLE_EVENT).toNotifications(aNotificationAccountParams())
assertThat(result).containsExactly(
val result = toNotifications(roomInvitation, aNotificationAccountParams()) OneShotNotification(
notification = expectedNotification,
assertThat(result).isEqualTo( key = AN_EVENT_ID.value,
listOf( summaryLine = A_SIMPLE_EVENT.description,
OneShotNotification( isNoisy = A_SIMPLE_EVENT.noisy,
notification = expectedNotification, timestamp = AN_INVITATION_EVENT.timestamp
key = AN_EVENT_ID.value,
summaryLine = A_SIMPLE_EVENT.description,
isNoisy = A_SIMPLE_EVENT.noisy,
timestamp = AN_INVITATION_EVENT.timestamp
)
) )
) )
} }
@ -116,14 +108,11 @@ class NotificationDataFactoryTest {
shouldBing = events.any { it.noisy }, shouldBing = events.any { it.noisy },
threadId = null, threadId = null,
) )
val roomWithMessage = listOf(A_MESSAGE_EVENT)
val fakeImageLoader = FakeImageLoader() val fakeImageLoader = FakeImageLoader()
val result = toNotifications( val result = listOf(A_MESSAGE_EVENT).toNotifications(
notificationAccountParams = aNotificationAccountParams( notificationAccountParams = aNotificationAccountParams(
user = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL), user = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
), ),
messages = roomWithMessage,
imageLoader = fakeImageLoader.getImageLoader(), imageLoader = fakeImageLoader.getImageLoader(),
) )
@ -134,17 +123,14 @@ class NotificationDataFactoryTest {
@Test @Test
fun `given a room with only redacted events when mapping to notification then is Empty`() = testWith(notificationDataFactory) { fun `given a room with only redacted events when mapping to notification then is Empty`() = testWith(notificationDataFactory) {
val redactedRoom = listOf(A_MESSAGE_EVENT.copy(isRedacted = true)) val redactedRoom = A_MESSAGE_EVENT.copy(isRedacted = true)
val fakeImageLoader = FakeImageLoader() val fakeImageLoader = FakeImageLoader()
val result = toNotifications( val result = listOf(redactedRoom).toNotifications(
notificationAccountParams = aNotificationAccountParams( notificationAccountParams = aNotificationAccountParams(
user = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL), user = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
), ),
messages = redactedRoom,
imageLoader = fakeImageLoader.getImageLoader(), imageLoader = fakeImageLoader.getImageLoader(),
) )
assertThat(result).isEmpty() assertThat(result).isEmpty()
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0) assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
} }
@ -178,11 +164,10 @@ class NotificationDataFactoryTest {
) )
val fakeImageLoader = FakeImageLoader() val fakeImageLoader = FakeImageLoader()
val result = toNotifications( val result = roomWithRedactedMessage.toNotifications(
notificationAccountParams = aNotificationAccountParams( notificationAccountParams = aNotificationAccountParams(
user = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL), user = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
), ),
messages = roomWithRedactedMessage,
imageLoader = fakeImageLoader.getImageLoader(), imageLoader = fakeImageLoader.getImageLoader(),
) )

View file

@ -40,39 +40,35 @@ class FakeNotificationDataFactory(
var fallbackEventToNotificationsResult: LambdaOneParamRecorder<List<FallbackNotifiableEvent>, List<OneShotNotification>> = var fallbackEventToNotificationsResult: LambdaOneParamRecorder<List<FallbackNotifiableEvent>, List<OneShotNotification>> =
lambdaRecorder { _ -> emptyList() }, lambdaRecorder { _ -> emptyList() },
) : NotificationDataFactory { ) : NotificationDataFactory {
override suspend fun toNotifications( override suspend fun List<NotifiableMessageEvent>.toNotifications(
messages: List<NotifiableMessageEvent>,
imageLoader: ImageLoader, imageLoader: ImageLoader,
notificationAccountParams: NotificationAccountParams, notificationAccountParams: NotificationAccountParams,
): List<RoomNotification> { ): List<RoomNotification> {
return messageEventToNotificationsResult(messages, imageLoader, notificationAccountParams) return messageEventToNotificationsResult(this, imageLoader, notificationAccountParams)
} }
@JvmName("toNotificationInvites") @JvmName("toNotificationInvites")
@Suppress("INAPPLICABLE_JVM_NAME") @Suppress("INAPPLICABLE_JVM_NAME")
override fun toNotifications( override fun List<InviteNotifiableEvent>.toNotifications(
invites: List<InviteNotifiableEvent>,
notificationAccountParams: NotificationAccountParams, notificationAccountParams: NotificationAccountParams,
): List<OneShotNotification> { ): List<OneShotNotification> {
return inviteToNotificationsResult(invites) return inviteToNotificationsResult(this)
} }
@JvmName("toNotificationSimpleEvents") @JvmName("toNotificationSimpleEvents")
@Suppress("INAPPLICABLE_JVM_NAME") @Suppress("INAPPLICABLE_JVM_NAME")
override fun toNotifications( override fun List<SimpleNotifiableEvent>.toNotifications(
simpleEvents: List<SimpleNotifiableEvent>,
notificationAccountParams: NotificationAccountParams, notificationAccountParams: NotificationAccountParams,
): List<OneShotNotification> { ): List<OneShotNotification> {
return simpleEventToNotificationsResult(simpleEvents) return simpleEventToNotificationsResult(this)
} }
@JvmName("toNotificationFallbackEvents") @JvmName("toNotificationFallbackEvents")
@Suppress("INAPPLICABLE_JVM_NAME") @Suppress("INAPPLICABLE_JVM_NAME")
override fun toNotifications( override fun List<FallbackNotifiableEvent>.toNotifications(
fallback: List<FallbackNotifiableEvent>,
notificationAccountParams: NotificationAccountParams, notificationAccountParams: NotificationAccountParams,
): List<OneShotNotification> { ): List<OneShotNotification> {
return fallbackEventToNotificationsResult(fallback) return fallbackEventToNotificationsResult(this)
} }
override fun createSummaryNotification( override fun createSummaryNotification(