porting notifications to chat engine

This commit is contained in:
Adam Brown 2022-10-12 20:52:02 +01:00
parent 86ad2a8a32
commit 4d033230e4
22 changed files with 122 additions and 96 deletions

View File

@ -180,9 +180,8 @@ internal class FeatureModules internal constructor(
val profileModule by unsafeLazy { ProfileModule(chatEngineModule.engine, trackingModule.errorTracker) }
val notificationsModule by unsafeLazy {
NotificationsModule(
chatEngineModule.engine,
imageLoaderModule.iconLoader(),
storeModule.value.roomStore(),
storeModule.value.overviewStore(),
context,
intentFactory = coreAndroidModule.intentFactory(),
dispatchers = coroutineDispatchers,

View File

@ -13,6 +13,9 @@ interface ChatEngine : TaskRunner {
fun invites(): Flow<InviteState>
fun messages(roomId: RoomId, disableReadReceipts: Boolean): Flow<MessengerState>
fun notificationsMessages(): Flow<UnreadNotifications>
fun notificationsInvites(): Flow<InviteNotification>
suspend fun login(request: LoginRequest): LoginResult
suspend fun me(forceRefresh: Boolean): Me
@ -63,3 +66,17 @@ interface PushHandler {
fun onNewToken(payload: JsonString)
fun onMessageReceived(eventId: EventId?, roomId: RoomId?)
}
typealias UnreadNotifications = Pair<Map<RoomOverview, List<RoomEvent>>, NotificationDiff>
data class NotificationDiff(
val unchanged: Map<RoomId, List<EventId>>,
val changedOrNew: Map<RoomId, List<EventId>>,
val removed: Map<RoomId, List<EventId>>,
val newRooms: Set<RoomId>
)
data class InviteNotification(
val content: String,
val roomId: RoomId
)

View File

@ -2,7 +2,7 @@ package fixture
import app.dapk.st.matrix.common.EventId
import app.dapk.st.matrix.common.RoomId
import app.dapk.st.notifications.NotificationDiff
import app.dapk.st.engine.NotificationDiff
object NotificationDiffFixtures {

View File

@ -1,6 +1,7 @@
applyAndroidLibraryModule(project)
dependencies {
implementation project(":chat-engine")
implementation project(':domains:store')
implementation project(":domains:android:work")
implementation project(':domains:android:push')
@ -10,12 +11,13 @@ dependencies {
implementation project(":features:messenger")
implementation project(":features:navigator")
implementation Dependencies.mavenCentral.kotlinSerializationJson
kotlinTest(it)
androidImportFixturesWorkaround(project, project(":core"))
androidImportFixturesWorkaround(project, project(":matrix:common"))
androidImportFixturesWorkaround(project, project(":matrix:services:sync"))
androidImportFixturesWorkaround(project, project(":chat-engine"))
androidImportFixturesWorkaround(project, project(":domains:android:stub"))
}

View File

@ -4,9 +4,9 @@ import android.app.Notification
import android.content.Context
import app.dapk.st.core.DeviceMeta
import app.dapk.st.core.whenPOrHigher
import app.dapk.st.engine.RoomOverview
import app.dapk.st.imageloader.IconLoader
import app.dapk.st.matrix.common.RoomId
import app.dapk.st.matrix.sync.RoomOverview
import app.dapk.st.navigator.IntentFactory
import java.time.Clock
@ -87,7 +87,7 @@ class NotificationFactory(
)
}
fun createInvite(inviteNotification: InviteNotification): AndroidNotification {
fun createInvite(inviteNotification: app.dapk.st.engine.InviteNotification): AndroidNotification {
val openAppIntent = intentFactory.notificationOpenApp(context)
return AndroidNotification(
channelId = INVITE_CHANNEL_ID,

View File

@ -10,7 +10,7 @@ class NotificationInviteRenderer(
private val androidNotificationBuilder: AndroidNotificationBuilder,
) {
fun render(inviteNotification: InviteNotification) {
fun render(inviteNotification: app.dapk.st.engine.InviteNotification) {
notificationManager.notify(
inviteNotification.roomId.value,
INVITE_NOTIFICATION_ID,
@ -18,7 +18,7 @@ class NotificationInviteRenderer(
)
}
private fun InviteNotification.toAndroidNotification() = androidNotificationBuilder.build(
private fun app.dapk.st.engine.InviteNotification.toAndroidNotification() = androidNotificationBuilder.build(
notificationFactory.createInvite(this)
)

View File

@ -5,9 +5,9 @@ import app.dapk.st.core.AppLogTag
import app.dapk.st.core.CoroutineDispatchers
import app.dapk.st.core.extensions.ifNull
import app.dapk.st.core.log
import app.dapk.st.engine.RoomEvent
import app.dapk.st.engine.RoomOverview
import app.dapk.st.matrix.common.RoomId
import app.dapk.st.matrix.sync.RoomEvent
import app.dapk.st.matrix.sync.RoomOverview
import kotlinx.coroutines.withContext
private const val SUMMARY_NOTIFICATION_ID = 101

View File

@ -3,8 +3,8 @@ package app.dapk.st.notifications
import android.annotation.SuppressLint
import app.dapk.st.core.DeviceMeta
import app.dapk.st.core.whenPOrHigher
import app.dapk.st.engine.RoomOverview
import app.dapk.st.imageloader.IconLoader
import app.dapk.st.matrix.sync.RoomOverview
import app.dapk.st.notifications.AndroidNotificationStyle.Inbox
import app.dapk.st.notifications.AndroidNotificationStyle.Messaging

View File

@ -5,16 +5,14 @@ import android.content.Context
import app.dapk.st.core.CoroutineDispatchers
import app.dapk.st.core.DeviceMeta
import app.dapk.st.core.ProvidableModule
import app.dapk.st.engine.ChatEngine
import app.dapk.st.imageloader.IconLoader
import app.dapk.st.matrix.sync.OverviewStore
import app.dapk.st.matrix.sync.RoomStore
import app.dapk.st.navigator.IntentFactory
import java.time.Clock
class NotificationsModule(
private val chatEngine: ChatEngine,
private val iconLoader: IconLoader,
private val roomStore: RoomStore,
private val overviewStore: OverviewStore,
private val context: Context,
private val intentFactory: IntentFactory,
private val dispatchers: CoroutineDispatchers,
@ -40,10 +38,9 @@ class NotificationsModule(
)
return RenderNotificationsUseCase(
notificationRenderer = notificationMessageRenderer,
observeRenderableUnreadEventsUseCase = ObserveUnreadNotificationsUseCaseImpl(roomStore),
notificationChannels = NotificationChannels(notificationManager),
observeInviteNotificationsUseCase = ObserveInviteNotificationsUseCaseImpl(overviewStore),
inviteRenderer = NotificationInviteRenderer(notificationManager, notificationFactory, androidNotificationBuilder)
inviteRenderer = NotificationInviteRenderer(notificationManager, notificationFactory, androidNotificationBuilder),
chatEngine = chatEngine,
)
}

View File

@ -1,7 +1,9 @@
package app.dapk.st.notifications
import app.dapk.st.matrix.sync.RoomEvent
import app.dapk.st.matrix.sync.RoomOverview
import app.dapk.st.engine.ChatEngine
import app.dapk.st.engine.NotificationDiff
import app.dapk.st.engine.RoomEvent
import app.dapk.st.engine.RoomOverview
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@ -9,18 +11,17 @@ import kotlinx.coroutines.flow.onEach
class RenderNotificationsUseCase(
private val notificationRenderer: NotificationMessageRenderer,
private val inviteRenderer: NotificationInviteRenderer,
private val observeRenderableUnreadEventsUseCase: ObserveUnreadNotificationsUseCase,
private val observeInviteNotificationsUseCase: ObserveInviteNotificationsUseCase,
private val chatEngine: ChatEngine,
private val notificationChannels: NotificationChannels,
) {
suspend fun listenForNotificationChanges(scope: CoroutineScope) {
notificationChannels.initChannels()
observeRenderableUnreadEventsUseCase()
chatEngine.notificationsMessages()
.onEach { (each, diff) -> renderUnreadChange(each, diff) }
.launchIn(scope)
observeInviteNotificationsUseCase()
chatEngine.notificationsInvites()
.onEach { inviteRenderer.render(it) }
.launchIn(scope)
}

View File

@ -1,7 +1,7 @@
package app.dapk.st.notifications
import app.dapk.st.engine.RoomEvent
import app.dapk.st.matrix.common.RoomMember
import app.dapk.st.matrix.sync.RoomEvent
class RoomEventsToNotifiableMapper {

View File

@ -137,7 +137,7 @@ class NotificationFactoryTest {
fakeIntentFactory.givenNotificationOpenApp(fakeContext.instance).returns(AN_OPEN_APP_INTENT)
val content = "Content message"
val result = notificationFactory.createInvite(
InviteNotification(
app.dapk.st.engine.InviteNotification(
content = content,
A_ROOM_ID,
)

View File

@ -1,5 +1,6 @@
package app.dapk.st.notifications
import app.dapk.st.engine.UnreadNotifications
import fake.*
import fixture.NotificationDiffFixtures.aNotificationDiff
import kotlinx.coroutines.test.TestScope
@ -19,12 +20,12 @@ class RenderNotificationsUseCaseTest {
private val fakeNotificationChannels = FakeNotificationChannels().also {
it.instance.expect { it.initChannels() }
}
private val fakeChatEngine = FakeChatEngine()
private val renderNotificationsUseCase = RenderNotificationsUseCase(
fakeNotificationMessageRenderer.instance,
fakeNotificationInviteRenderer.instance,
fakeObserveUnreadNotificationsUseCase,
fakeObserveInviteNotificationsUseCase,
fakeChatEngine,
fakeNotificationChannels.instance,
)

View File

@ -2,14 +2,14 @@ package fake
import app.dapk.st.notifications.NotificationMessageRenderer
import app.dapk.st.notifications.NotificationState
import app.dapk.st.notifications.UnreadNotifications
import app.dapk.st.engine.UnreadNotifications
import io.mockk.coVerify
import io.mockk.mockk
class FakeNotificationMessageRenderer {
val instance = mockk<NotificationMessageRenderer>()
fun verifyRenders(vararg unreadNotifications: UnreadNotifications) {
fun verifyRenders(vararg unreadNotifications: app.dapk.st.engine.UnreadNotifications) {
unreadNotifications.forEach { unread ->
coVerify {
instance.render(

View File

@ -1,10 +1,10 @@
package fake
import app.dapk.st.notifications.ObserveInviteNotificationsUseCase
import app.dapk.st.engine.ObserveInviteNotificationsUseCase
import io.mockk.coEvery
import io.mockk.mockk
import test.delegateEmit
class FakeObserveInviteNotificationsUseCase : ObserveInviteNotificationsUseCase by mockk() {
class FakeObserveInviteNotificationsUseCase : app.dapk.st.engine.ObserveInviteNotificationsUseCase by mockk() {
fun given() = coEvery { this@FakeObserveInviteNotificationsUseCase.invoke() }.delegateEmit()
}

View File

@ -1,10 +1,10 @@
package fake
import app.dapk.st.notifications.ObserveUnreadNotificationsUseCase
import app.dapk.st.engine.ObserveUnreadNotificationsUseCase
import io.mockk.coEvery
import io.mockk.mockk
import test.delegateEmit
class FakeObserveUnreadNotificationsUseCase : ObserveUnreadNotificationsUseCase by mockk() {
class FakeObserveUnreadNotificationsUseCase : app.dapk.st.engine.ObserveUnreadNotificationsUseCase by mockk() {
fun given() = coEvery { this@FakeObserveUnreadNotificationsUseCase.invoke() }.delegateEmit()
}

View File

@ -41,6 +41,8 @@ class MatrixEngine internal constructor(
private val matrixMediaDecrypter: Lazy<MatrixMediaDecrypter>,
private val matrixPushHandler: Lazy<MatrixPushHandler>,
private val inviteUseCase: Lazy<InviteUseCase>,
private val notificationMessagesUseCase: Lazy<ObserveUnreadNotificationsUseCase>,
private val notificationInvitesUseCase: Lazy<ObserveInviteNotificationsUseCase>,
) : ChatEngine {
override fun directory() = directoryUseCase.value.state()
@ -50,6 +52,14 @@ class MatrixEngine internal constructor(
return timelineUseCase.value.fetch(roomId, isReadReceiptsDisabled = disableReadReceipts)
}
override fun notificationsMessages(): Flow<UnreadNotifications> {
return notificationMessagesUseCase.value.invoke()
}
override fun notificationsInvites(): Flow<InviteNotification> {
return notificationInvitesUseCase.value.invoke()
}
override suspend fun login(request: LoginRequest): LoginResult {
return matrix.value.authService().login(request.engine()).engine()
}
@ -190,6 +200,8 @@ class MatrixEngine internal constructor(
mediaDecrypter,
pushHandler,
invitesUseCase,
unsafeLazy { ObserveUnreadNotificationsUseCaseImpl(roomStore) },
unsafeLazy { ObserveInviteNotificationsUseCaseImpl(overviewStore) },
)
}

View File

@ -1,17 +1,16 @@
package app.dapk.st.notifications
package app.dapk.st.engine
import app.dapk.st.matrix.common.RoomId
import app.dapk.st.matrix.sync.InviteMeta
import app.dapk.st.matrix.sync.OverviewStore
import app.dapk.st.matrix.sync.RoomInvite
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.*
internal typealias ObserveInviteNotificationsUseCase = suspend () -> Flow<InviteNotification>
internal typealias ObserveInviteNotificationsUseCase = () -> Flow<InviteNotification>
class ObserveInviteNotificationsUseCaseImpl(private val overviewStore: OverviewStore) : ObserveInviteNotificationsUseCase {
override suspend fun invoke(): Flow<InviteNotification> {
override fun invoke(): Flow<InviteNotification> {
return overviewStore.latestInvites()
.diff()
.drop(1)
@ -43,8 +42,3 @@ class ObserveInviteNotificationsUseCaseImpl(private val overviewStore: OverviewS
private fun <T> Flow<Set<T>>.flatten() = this.flatMapConcat { items ->
flow { items.forEach { this.emit(it) } }
}
data class InviteNotification(
val content: String,
val roomId: RoomId
)

View File

@ -1,4 +1,4 @@
package app.dapk.st.notifications
package app.dapk.st.engine
import app.dapk.st.core.AppLogTag
import app.dapk.st.core.extensions.clearAndPutAll
@ -6,17 +6,16 @@ import app.dapk.st.core.extensions.containsKey
import app.dapk.st.core.log
import app.dapk.st.matrix.common.EventId
import app.dapk.st.matrix.common.RoomId
import app.dapk.st.matrix.sync.RoomEvent
import app.dapk.st.matrix.sync.RoomOverview
import app.dapk.st.matrix.sync.RoomStore
import kotlinx.coroutines.flow.*
import app.dapk.st.matrix.sync.RoomEvent as MatrixRoomEvent
import app.dapk.st.matrix.sync.RoomOverview as MatrixRoomOverview
typealias UnreadNotifications = Pair<Map<RoomOverview, List<RoomEvent>>, NotificationDiff>
internal typealias ObserveUnreadNotificationsUseCase = suspend () -> Flow<UnreadNotifications>
internal typealias ObserveUnreadNotificationsUseCase = () -> Flow<UnreadNotifications>
class ObserveUnreadNotificationsUseCaseImpl(private val roomStore: RoomStore) : ObserveUnreadNotificationsUseCase {
override suspend fun invoke(): Flow<UnreadNotifications> {
override fun invoke(): Flow<UnreadNotifications> {
return roomStore.observeUnread()
.mapWithDiff()
.avoidShowingPreviousNotificationsOnLaunch()
@ -25,28 +24,7 @@ class ObserveUnreadNotificationsUseCaseImpl(private val roomStore: RoomStore) :
}
private fun Flow<UnreadNotifications>.onlyRenderableChanges(): Flow<UnreadNotifications> {
val inferredCurrentNotifications = mutableMapOf<RoomId, List<RoomEvent>>()
return this
.filter { (_, diff) ->
when {
diff.changedOrNew.isEmpty() && diff.removed.isEmpty() -> {
log(AppLogTag.NOTIFICATION, "Ignoring unread change due to no renderable changes")
false
}
inferredCurrentNotifications.isEmpty() && diff.removed.isNotEmpty() -> {
log(AppLogTag.NOTIFICATION, "Ignoring unread change due to no currently showing messages and changes are all messages marked as read")
false
}
else -> true
}
}
.onEach { (allUnread, _) -> inferredCurrentNotifications.clearAndPutAll(allUnread.mapKeys { it.key.roomId }) }
}
private fun Flow<Map<RoomOverview, List<RoomEvent>>>.mapWithDiff(): Flow<Pair<Map<RoomOverview, List<RoomEvent>>, NotificationDiff>> {
private fun Flow<Map<MatrixRoomOverview, List<MatrixRoomEvent>>>.mapWithDiff(): Flow<Pair<Map<MatrixRoomOverview, List<MatrixRoomEvent>>, NotificationDiff>> {
val previousUnreadEvents = mutableMapOf<RoomId, List<TimestampedEventId>>()
return this.map { each ->
val allUnreadIds = each.toTimestampedIds()
@ -83,19 +61,39 @@ private fun Map<RoomId, List<TimestampedEventId>>?.toLatestTimestamps() = this?.
private fun Map<RoomId, List<TimestampedEventId>>.toEventIds() = this.mapValues { it.value.map { it.first } }
private fun Map<RoomOverview, List<RoomEvent>>.toTimestampedIds() = this
private fun Map<MatrixRoomOverview, List<MatrixRoomEvent>>.toTimestampedIds() = this
.mapValues { it.value.toEventIds() }
.mapKeys { it.key.roomId }
private fun List<RoomEvent>.toEventIds() = this.map { it.eventId to it.utcTimestamp }
private fun List<MatrixRoomEvent>.toEventIds() = this.map { it.eventId to it.utcTimestamp }
private fun <T> Flow<T>.avoidShowingPreviousNotificationsOnLaunch() = drop(1)
data class NotificationDiff(
val unchanged: Map<RoomId, List<EventId>>,
val changedOrNew: Map<RoomId, List<EventId>>,
val removed: Map<RoomId, List<EventId>>,
val newRooms: Set<RoomId>
)
private fun Flow<Pair<Map<MatrixRoomOverview, List<MatrixRoomEvent>>, NotificationDiff>>.onlyRenderableChanges(): Flow<UnreadNotifications> {
val inferredCurrentNotifications = mutableMapOf<RoomId, List<MatrixRoomEvent>>()
return this
.filter { (_, diff) ->
when {
diff.changedOrNew.isEmpty() && diff.removed.isEmpty() -> {
log(AppLogTag.NOTIFICATION, "Ignoring unread change due to no renderable changes")
false
}
inferredCurrentNotifications.isEmpty() && diff.removed.isNotEmpty() -> {
log(AppLogTag.NOTIFICATION, "Ignoring unread change due to no currently showing messages and changes are all messages marked as read")
false
}
else -> true
}
}
.onEach { (allUnread, _) -> inferredCurrentNotifications.clearAndPutAll(allUnread.mapKeys { it.key.roomId }) }
.map {
val engineModels = it.first
.mapKeys { it.key.engine() }
.mapValues { it.value.map { it.engine() } }
engineModels to it.second
}
}
typealias TimestampedEventId = Pair<EventId, Long>

View File

@ -1,24 +1,27 @@
package app.dapk.st.notifications
package app.dapk.st.engine
import app.dapk.st.matrix.sync.RoomEvent
import app.dapk.st.matrix.sync.RoomOverview
import fake.FakeRoomStore
import fixture.NotificationDiffFixtures.aNotificationDiff
import fixture.aMatrixRoomOverview
import fixture.aRoomId
import fixture.aRoomMessageEvent
import fixture.aRoomOverview
import fixture.anEventId
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.test.runTest
import org.amshove.kluent.shouldBeEqualTo
import org.junit.Test
import app.dapk.st.matrix.sync.RoomEvent as MatrixRoomEvent
import app.dapk.st.matrix.sync.RoomOverview as MatrixRoomOverview
private val NO_UNREADS = emptyMap<RoomOverview, List<RoomEvent>>()
private val NO_UNREADS = emptyMap<MatrixRoomOverview, List<MatrixRoomEvent>>()
private val A_MESSAGE = aRoomMessageEvent(eventId = anEventId("1"), content = "hello", utcTimestamp = 1000)
private val A_MESSAGE_2 = aRoomMessageEvent(eventId = anEventId("2"), content = "world", utcTimestamp = 2000)
private val A_ROOM_OVERVIEW = aRoomOverview(roomId = aRoomId("1"))
private val A_ROOM_OVERVIEW_2 = aRoomOverview(roomId = aRoomId("2"))
private val A_ROOM_OVERVIEW = aMatrixRoomOverview(roomId = aRoomId("1"))
private val A_ROOM_OVERVIEW_2 = aMatrixRoomOverview(roomId = aRoomId("2"))
private fun MatrixRoomOverview.withUnreads(vararg events: MatrixRoomEvent) = mapOf(this to events.toList())
private fun MatrixRoomOverview.toDiff(vararg events: MatrixRoomEvent) = mapOf(this.roomId to events.map { it.eventId })
class ObserveUnreadRenderNotificationsUseCaseTest {
@ -33,7 +36,7 @@ class ObserveUnreadRenderNotificationsUseCaseTest {
val result = useCase.invoke().toList()
result shouldBeEqualTo listOf(
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE) to aNotificationDiff(
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE).engine() to aNotificationDiff(
changedOrNew = A_ROOM_OVERVIEW.toDiff(A_MESSAGE),
newRooms = setOf(A_ROOM_OVERVIEW.roomId)
)
@ -47,11 +50,11 @@ class ObserveUnreadRenderNotificationsUseCaseTest {
val result = useCase.invoke().toList()
result shouldBeEqualTo listOf(
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE) to aNotificationDiff(
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE).engine() to aNotificationDiff(
changedOrNew = A_ROOM_OVERVIEW.toDiff(A_MESSAGE),
newRooms = setOf(A_ROOM_OVERVIEW.roomId)
),
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE, A_MESSAGE_2) to aNotificationDiff(changedOrNew = A_ROOM_OVERVIEW.toDiff(A_MESSAGE_2))
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE, A_MESSAGE_2).engine() to aNotificationDiff(changedOrNew = A_ROOM_OVERVIEW.toDiff(A_MESSAGE_2))
)
}
@ -64,7 +67,7 @@ class ObserveUnreadRenderNotificationsUseCaseTest {
val result = useCase.invoke().toList()
result shouldBeEqualTo listOf(
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE, A_MESSAGE_2) to aNotificationDiff(changedOrNew = A_ROOM_OVERVIEW.toDiff(A_MESSAGE_2))
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE, A_MESSAGE_2).engine() to aNotificationDiff(changedOrNew = A_ROOM_OVERVIEW.toDiff(A_MESSAGE_2))
)
}
@ -92,7 +95,7 @@ class ObserveUnreadRenderNotificationsUseCaseTest {
val result = useCase.invoke().toList()
result shouldBeEqualTo listOf(
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE) to aNotificationDiff(
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE).engine() to aNotificationDiff(
changedOrNew = A_ROOM_OVERVIEW.toDiff(A_MESSAGE),
newRooms = setOf(A_ROOM_OVERVIEW.roomId)
),
@ -110,8 +113,10 @@ class ObserveUnreadRenderNotificationsUseCaseTest {
result shouldBeEqualTo emptyList()
}
private fun givenNoInitialUnreads(vararg unreads: Map<RoomOverview, List<RoomEvent>>) = fakeRoomStore.givenUnreadEvents(flowOf(NO_UNREADS, *unreads))
private fun givenNoInitialUnreads(vararg unreads: Map<MatrixRoomOverview, List<MatrixRoomEvent>>) =
fakeRoomStore.givenUnreadEvents(flowOf(NO_UNREADS, *unreads))
}
private fun RoomOverview.withUnreads(vararg events: RoomEvent) = mapOf(this to events.toList())
private fun RoomOverview.toDiff(vararg events: RoomEvent) = mapOf(this.roomId to events.map { it.eventId })
private fun Map<MatrixRoomOverview, List<MatrixRoomEvent>>.engine() = this
.mapKeys { it.key.engine() }
.mapValues { it.value.map { it.engine() } }

View File

@ -7,7 +7,7 @@ import app.dapk.st.matrix.common.RoomMember
import app.dapk.st.matrix.sync.LastMessage
import app.dapk.st.matrix.sync.RoomOverview
fun aRoomOverview(
fun aMatrixRoomOverview(
roomId: RoomId = aRoomId(),
roomCreationUtc: Long = 0L,
roomName: String? = null,

View File

@ -5,6 +5,6 @@ import app.dapk.st.matrix.sync.RoomOverview
import app.dapk.st.matrix.sync.RoomState
fun aRoomState(
roomOverview: RoomOverview = aRoomOverview(),
roomOverview: RoomOverview = aMatrixRoomOverview(),
events: List<RoomEvent> = listOf(aRoomMessageEvent()),
) = RoomState(roomOverview, events)