porting notifications to chat engine
This commit is contained in:
parent
86ad2a8a32
commit
4d033230e4
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -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 {
|
||||
|
|
@ -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"))
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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) },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -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>
|
|
@ -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() } }
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
Loading…
Reference in New Issue