mirror of
https://github.com/ouchadam/small-talk.git
synced 2025-02-21 14:40:50 +01:00
flattening directory use case syncing into the main logic, adding tests around directory view model
This commit is contained in:
parent
e0a7830b5d
commit
7fff5face4
@ -91,7 +91,7 @@ internal class RoomPersistence(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun observeUnreadCountById(): Flow<Map<RoomId, Int>> {
|
||||
override fun observeUnreadCountById(): Flow<Map<RoomId, Int>> {
|
||||
return database.roomEventQueries.selectAllUnread()
|
||||
.asFlow()
|
||||
.mapToList()
|
||||
|
@ -10,4 +10,14 @@ dependencies {
|
||||
implementation project(":core")
|
||||
implementation project(":design-library")
|
||||
implementation("io.coil-kt:coil-compose:1.4.0")
|
||||
|
||||
kotlinTest(it)
|
||||
|
||||
androidImportFixturesWorkaround(project, project(":matrix:services:sync"))
|
||||
androidImportFixturesWorkaround(project, project(":matrix:services:message"))
|
||||
androidImportFixturesWorkaround(project, project(":matrix:common"))
|
||||
androidImportFixturesWorkaround(project, project(":core"))
|
||||
androidImportFixturesWorkaround(project, project(":domains:store"))
|
||||
androidImportFixturesWorkaround(project, project(":domains:android:viewmodel"))
|
||||
androidImportFixturesWorkaround(project, project(":domains:android:stub"))
|
||||
}
|
@ -10,6 +10,7 @@ import app.dapk.st.matrix.sync.*
|
||||
import app.dapk.st.matrix.sync.SyncService.SyncEvent.Typing
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
@JvmInline
|
||||
value class UnreadCount(val value: Int)
|
||||
@ -26,18 +27,14 @@ class DirectoryUseCase(
|
||||
private val roomStore: RoomStore,
|
||||
) {
|
||||
|
||||
suspend fun startSyncing(): Flow<Unit> {
|
||||
return syncService.startSyncing()
|
||||
}
|
||||
|
||||
suspend fun state(): Flow<DirectoryState> {
|
||||
val userId = credentialsStore.credentials()!!.userId
|
||||
fun state(): Flow<DirectoryState> {
|
||||
return combine(
|
||||
syncService.startSyncing().map { credentialsStore.credentials()!!.userId },
|
||||
syncService.overview(),
|
||||
messageService.localEchos(),
|
||||
roomStore.observeUnreadCountById(),
|
||||
syncService.events()
|
||||
) { overviewState, localEchos, unread, events ->
|
||||
) { userId, overviewState, localEchos, unread, events ->
|
||||
overviewState.mergeWithLocalEchos(localEchos, userId).map { roomOverview ->
|
||||
RoomFoo(
|
||||
overview = roomOverview,
|
||||
|
@ -4,6 +4,8 @@ import androidx.lifecycle.viewModelScope
|
||||
import app.dapk.st.directory.DirectoryScreenState.Content
|
||||
import app.dapk.st.directory.DirectoryScreenState.EmptyLoading
|
||||
import app.dapk.st.viewmodel.DapkViewModel
|
||||
import app.dapk.st.viewmodel.MutableStateFactory
|
||||
import app.dapk.st.viewmodel.defaultStateFactory
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -12,18 +14,16 @@ import kotlinx.coroutines.launch
|
||||
class DirectoryViewModel(
|
||||
private val shortcutHandler: ShortcutHandler,
|
||||
private val directoryUseCase: DirectoryUseCase,
|
||||
factory: MutableStateFactory<DirectoryScreenState> = defaultStateFactory(),
|
||||
) : DapkViewModel<DirectoryScreenState, DirectoryEvent>(
|
||||
initialState = EmptyLoading
|
||||
initialState = EmptyLoading,
|
||||
factory,
|
||||
) {
|
||||
|
||||
private var syncJob: Job? = null
|
||||
|
||||
fun start() {
|
||||
syncJob = viewModelScope.launch {
|
||||
directoryUseCase.startSyncing().collect()
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
directoryUseCase.state().onEach {
|
||||
shortcutHandler.onDirectoryUpdate(it.map { it.overview })
|
||||
if (it.isNotEmpty()) {
|
||||
|
@ -13,7 +13,6 @@ class ShortcutHandler(private val context: Context) {
|
||||
private val cachedRoomIds = mutableListOf<RoomId>()
|
||||
|
||||
fun onDirectoryUpdate(overviews: List<RoomOverview>) {
|
||||
|
||||
val update = overviews.map { it.roomId }
|
||||
|
||||
if (cachedRoomIds != update) {
|
||||
|
@ -0,0 +1,52 @@
|
||||
package app.dapk.st.directory
|
||||
|
||||
import ViewModelTest
|
||||
import fixture.aRoomOverview
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.junit.Test
|
||||
import test.delegateReturn
|
||||
|
||||
private val AN_OVERVIEW = aRoomOverview()
|
||||
private val AN_OVERVIEW_STATE = RoomFoo(AN_OVERVIEW, UnreadCount(1), null)
|
||||
|
||||
class DirectoryViewModelTest {
|
||||
|
||||
private val runViewModelTest = ViewModelTest()
|
||||
private val fakeDirectoryUseCase = FakeDirectoryUseCase()
|
||||
private val fakeShortcutHandler = FakeShortcutHandler()
|
||||
|
||||
private val viewModel = DirectoryViewModel(
|
||||
fakeShortcutHandler.instance,
|
||||
fakeDirectoryUseCase.instance,
|
||||
runViewModelTest.testMutableStateFactory(),
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `when creating view model, then initial state is empty loading`() = runViewModelTest {
|
||||
viewModel.test()
|
||||
|
||||
assertInitialState(DirectoryScreenState.EmptyLoading)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when starting, then updates shortcuts and emits room state`() = runViewModelTest {
|
||||
fakeShortcutHandler.instance.expectUnit { it.onDirectoryUpdate(listOf(AN_OVERVIEW)) }
|
||||
fakeDirectoryUseCase.given().returns(flowOf(listOf(AN_OVERVIEW_STATE)))
|
||||
|
||||
viewModel.test().start()
|
||||
|
||||
assertStates(DirectoryScreenState.Content(listOf(AN_OVERVIEW_STATE)))
|
||||
verifyExpects()
|
||||
}
|
||||
}
|
||||
|
||||
class FakeShortcutHandler {
|
||||
val instance = mockk<ShortcutHandler>()
|
||||
}
|
||||
|
||||
class FakeDirectoryUseCase {
|
||||
val instance = mockk<DirectoryUseCase>()
|
||||
fun given() = every { instance.state() }.delegateReturn()
|
||||
}
|
@ -13,7 +13,7 @@ interface RoomStore {
|
||||
suspend fun insertUnread(roomId: RoomId, eventIds: List<EventId>)
|
||||
suspend fun markRead(roomId: RoomId)
|
||||
suspend fun observeUnread(): Flow<Map<RoomOverview, List<RoomEvent>>>
|
||||
suspend fun observeUnreadCountById(): Flow<Map<RoomId, Int>>
|
||||
fun observeUnreadCountById(): Flow<Map<RoomId, Int>>
|
||||
suspend fun observeEvent(eventId: EventId): Flow<EventId>
|
||||
suspend fun findEvent(eventId: EventId): RoomEvent?
|
||||
|
||||
|
@ -8,7 +8,6 @@ import app.dapk.st.matrix.MatrixServiceInstaller
|
||||
import app.dapk.st.matrix.ServiceDepFactory
|
||||
import app.dapk.st.matrix.common.*
|
||||
import app.dapk.st.matrix.sync.internal.DefaultSyncService
|
||||
import app.dapk.st.matrix.sync.internal.SideEffectFlowIterator
|
||||
import app.dapk.st.matrix.sync.internal.request.*
|
||||
import app.dapk.st.matrix.sync.internal.room.MessageDecrypter
|
||||
import app.dapk.st.matrix.sync.internal.room.MissingMessageDecrypter
|
||||
@ -20,7 +19,7 @@ private val SERVICE_KEY = SyncService::class
|
||||
interface SyncService : MatrixService {
|
||||
|
||||
suspend fun invites(): Flow<InviteState>
|
||||
suspend fun overview(): Flow<OverviewState>
|
||||
fun overview(): Flow<OverviewState>
|
||||
fun room(roomId: RoomId): Flow<RoomState>
|
||||
fun startSyncing(): Flow<Unit>
|
||||
fun events(): Flow<List<SyncEvent>>
|
||||
|
@ -100,7 +100,7 @@ internal class DefaultSyncService(
|
||||
|
||||
override fun startSyncing() = syncFlow
|
||||
override suspend fun invites() = overviewStore.latestInvites()
|
||||
override suspend fun overview() = overviewStore.latest()
|
||||
override fun overview() = overviewStore.latest()
|
||||
override fun room(roomId: RoomId) = roomStore.latest(roomId)
|
||||
override fun events() = syncEventsFlow
|
||||
override suspend fun observeEvent(eventId: EventId) = roomStore.observeEvent(eventId)
|
||||
|
Loading…
x
Reference in New Issue
Block a user