sdk : allow passing coroutineScope to RoomList
This commit is contained in:
@@ -8,7 +8,9 @@
|
||||
|
||||
package io.element.android.features.home.impl.search
|
||||
|
||||
import dev.zacsweers.metro.Inject
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedFactory
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.features.home.impl.datasource.RoomListRoomSummaryFactory
|
||||
import io.element.android.features.home.impl.model.RoomListRoomSummary
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
@@ -18,6 +20,7 @@ import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.api.roomlist.loadAllIncrementally
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
@@ -25,16 +28,23 @@ import kotlinx.coroutines.flow.map
|
||||
|
||||
private const val PAGE_SIZE = 30
|
||||
|
||||
@Inject
|
||||
@AssistedInject
|
||||
class RoomListSearchDataSource(
|
||||
@Assisted coroutineScope: CoroutineScope,
|
||||
roomListService: RoomListService,
|
||||
coroutineDispatchers: CoroutineDispatchers,
|
||||
private val roomSummaryFactory: RoomListRoomSummaryFactory,
|
||||
) {
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(coroutineScope: CoroutineScope): RoomListSearchDataSource
|
||||
}
|
||||
|
||||
private val roomList = roomListService.createRoomList(
|
||||
pageSize = PAGE_SIZE,
|
||||
initialFilter = RoomListFilter.None,
|
||||
source = RoomList.Source.All,
|
||||
coroutineScope = coroutineScope
|
||||
)
|
||||
|
||||
val roomSummaries: Flow<ImmutableList<RoomListRoomSummary>> = roomList.filteredSummaries
|
||||
|
||||
@@ -16,6 +16,7 @@ import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
@@ -23,7 +24,7 @@ import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Inject
|
||||
class RoomListSearchPresenter(
|
||||
private val dataSource: RoomListSearchDataSource,
|
||||
private val dataSourceFactory: RoomListSearchDataSource.Factory,
|
||||
) : Presenter<RoomListSearchState> {
|
||||
@Composable
|
||||
override fun present(): RoomListSearchState {
|
||||
@@ -33,6 +34,9 @@ class RoomListSearchPresenter(
|
||||
}
|
||||
val searchQuery = rememberTextFieldState()
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val dataSource = remember { dataSourceFactory.create(coroutineScope) }
|
||||
|
||||
LaunchedEffect(isSearchActive) {
|
||||
dataSource.setIsActive(isSearchActive)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
||||
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
@@ -122,13 +123,18 @@ fun TestScope.createRoomListSearchPresenter(
|
||||
roomListService: RoomListService = FakeRoomListService(),
|
||||
): RoomListSearchPresenter {
|
||||
return RoomListSearchPresenter(
|
||||
dataSource = RoomListSearchDataSource(
|
||||
roomListService = roomListService,
|
||||
roomSummaryFactory = aRoomListRoomSummaryFactory(
|
||||
dateFormatter = FakeDateFormatter(),
|
||||
roomLatestEventFormatter = FakeRoomLatestEventFormatter(),
|
||||
),
|
||||
coroutineDispatchers = testCoroutineDispatchers(),
|
||||
),
|
||||
dataSourceFactory = object : RoomListSearchDataSource.Factory {
|
||||
override fun create(coroutineScope: CoroutineScope): RoomListSearchDataSource {
|
||||
return RoomListSearchDataSource(
|
||||
roomListService = roomListService,
|
||||
roomSummaryFactory = aRoomListRoomSummaryFactory(
|
||||
dateFormatter = FakeDateFormatter(),
|
||||
roomLatestEventFormatter = FakeRoomLatestEventFormatter(),
|
||||
),
|
||||
coroutineDispatchers = testCoroutineDispatchers(),
|
||||
coroutineScope = coroutineScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ package io.element.android.libraries.matrix.api.roomlist
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
@@ -39,11 +40,13 @@ interface RoomListService {
|
||||
* @param pageSize the number of rooms to load at once.
|
||||
* @param initialFilter the initial filter to apply to the rooms.
|
||||
* @param source the source of the rooms, either all rooms or invites.
|
||||
* @param coroutineScope the coroutine scope to use for the room list operations.
|
||||
*/
|
||||
fun createRoomList(
|
||||
pageSize: Int,
|
||||
initialFilter: RoomListFilter,
|
||||
source: RoomList.Source,
|
||||
coroutineScope: CoroutineScope,
|
||||
): DynamicRoomList
|
||||
|
||||
/**
|
||||
|
||||
@@ -192,7 +192,6 @@ class RustMatrixClient(
|
||||
sessionDispatcher = sessionDispatcher,
|
||||
roomListFactory = RoomListFactory(
|
||||
innerRoomListService = innerRoomListService,
|
||||
sessionCoroutineScope = sessionCoroutineScope,
|
||||
analyticsService = analyticsService,
|
||||
),
|
||||
roomSyncSubscriber = roomSyncSubscriber,
|
||||
|
||||
@@ -38,7 +38,6 @@ private val ROOM_LIST_RUST_FILTERS = listOf(
|
||||
|
||||
internal class RoomListFactory(
|
||||
private val innerRoomListService: RoomListService,
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
private val analyticsService: AnalyticsService,
|
||||
) {
|
||||
private val roomSummaryFactory: RoomSummaryFactory = RoomSummaryFactory()
|
||||
@@ -49,7 +48,7 @@ internal class RoomListFactory(
|
||||
fun createRoomList(
|
||||
pageSize: Int,
|
||||
coroutineContext: CoroutineContext,
|
||||
coroutineScope: CoroutineScope = sessionCoroutineScope,
|
||||
coroutineScope: CoroutineScope,
|
||||
initialFilter: RoomListFilter = RoomListFilter.all(),
|
||||
innerProvider: suspend () -> InnerRoomList
|
||||
): DynamicRoomList {
|
||||
|
||||
@@ -35,17 +35,19 @@ internal class RustRoomListService(
|
||||
private val sessionDispatcher: CoroutineDispatcher,
|
||||
private val roomListFactory: RoomListFactory,
|
||||
private val roomSyncSubscriber: RoomSyncSubscriber,
|
||||
sessionCoroutineScope: CoroutineScope,
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
) : RoomListService {
|
||||
override fun createRoomList(
|
||||
pageSize: Int,
|
||||
initialFilter: RoomListFilter,
|
||||
source: RoomList.Source
|
||||
source: RoomList.Source,
|
||||
coroutineScope: CoroutineScope,
|
||||
): DynamicRoomList {
|
||||
return roomListFactory.createRoomList(
|
||||
pageSize = pageSize,
|
||||
initialFilter = initialFilter,
|
||||
coroutineContext = sessionDispatcher,
|
||||
coroutineScope = coroutineScope,
|
||||
) {
|
||||
when (source) {
|
||||
RoomList.Source.All -> innerRoomListService.allRooms()
|
||||
@@ -60,6 +62,7 @@ internal class RustRoomListService(
|
||||
override val allRooms: DynamicRoomList = roomListFactory.createRoomList(
|
||||
pageSize = DEFAULT_PAGE_SIZE,
|
||||
coroutineContext = sessionDispatcher,
|
||||
coroutineScope = sessionCoroutineScope,
|
||||
) {
|
||||
innerRoomListService.allRooms()
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ class RoomListFactoryTest {
|
||||
fun `createRoomList should work`() = runTest {
|
||||
val sut = RoomListFactory(
|
||||
innerRoomListService = FakeFfiRoomListService(),
|
||||
sessionCoroutineScope = backgroundScope,
|
||||
analyticsService = FakeAnalyticsService(),
|
||||
)
|
||||
sut.createRoomList(
|
||||
pageSize = 10,
|
||||
coroutineContext = EmptyCoroutineContext,
|
||||
coroutineScope = backgroundScope,
|
||||
) {
|
||||
FakeFfiRoomList()
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ private fun TestScope.createRustRoomListService(
|
||||
sessionDispatcher = StandardTestDispatcher(testScheduler),
|
||||
roomListFactory = RoomListFactory(
|
||||
innerRoomListService = roomListService,
|
||||
sessionCoroutineScope = backgroundScope,
|
||||
analyticsService = FakeAnalyticsService(),
|
||||
),
|
||||
roomSyncSubscriber = RoomSyncSubscriber(
|
||||
|
||||
@@ -14,6 +14,7 @@ import io.element.android.libraries.matrix.api.roomlist.RoomList
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@@ -44,7 +45,8 @@ class FakeRoomListService(
|
||||
override fun createRoomList(
|
||||
pageSize: Int,
|
||||
initialFilter: RoomListFilter,
|
||||
source: RoomList.Source
|
||||
source: RoomList.Source,
|
||||
coroutineScope: CoroutineScope,
|
||||
): DynamicRoomList {
|
||||
return when (source) {
|
||||
RoomList.Source.All -> allRooms
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
package io.element.android.libraries.roomselect.impl
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
@@ -17,6 +19,7 @@ import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.appyx.launchMolecule
|
||||
import io.element.android.libraries.architecture.callback
|
||||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
@@ -36,11 +39,12 @@ class RoomSelectNode(
|
||||
|
||||
private val inputs: Inputs = inputs()
|
||||
private val presenter = presenterFactory.create(inputs.mode)
|
||||
private val stateFlow = launchMolecule { presenter.present() }
|
||||
private val callback: RoomSelectEntryPoint.Callback = callback()
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val state = presenter.present()
|
||||
val state by stateFlow.collectAsState()
|
||||
RoomSelectView(
|
||||
state = state,
|
||||
onDismiss = callback::onCancel,
|
||||
|
||||
@@ -16,6 +16,7 @@ import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedFactory
|
||||
@@ -31,7 +32,7 @@ import kotlinx.collections.immutable.toImmutableList
|
||||
@AssistedInject
|
||||
class RoomSelectPresenter(
|
||||
@Assisted private val mode: RoomSelectMode,
|
||||
private val dataSource: RoomSelectSearchDataSource,
|
||||
private val dataSourceFactory: RoomSelectSearchDataSource.Factory,
|
||||
) : Presenter<RoomSelectState> {
|
||||
@AssistedFactory
|
||||
fun interface Factory {
|
||||
@@ -44,9 +45,8 @@ class RoomSelectPresenter(
|
||||
var searchQuery by remember { mutableStateOf("") }
|
||||
var isSearchActive by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
dataSource.load()
|
||||
}
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val dataSource = remember { dataSourceFactory.create(coroutineScope) }
|
||||
|
||||
LaunchedEffect(searchQuery) {
|
||||
dataSource.setSearchQuery(searchQuery)
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
|
||||
package io.element.android.libraries.roomselect.impl
|
||||
|
||||
import dev.zacsweers.metro.Inject
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedFactory
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
||||
@@ -19,6 +21,7 @@ import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
|
||||
import io.element.android.libraries.matrix.ui.model.toSelectRoomInfo
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
@@ -30,16 +33,25 @@ private const val PAGE_SIZE = 30
|
||||
* DataSource for RoomSummaryDetails that can be filtered by a search query,
|
||||
* and which only includes rooms the user has joined.
|
||||
*/
|
||||
@Inject
|
||||
@AssistedInject
|
||||
class RoomSelectSearchDataSource(
|
||||
@Assisted coroutineScope: CoroutineScope,
|
||||
roomListService: RoomListService,
|
||||
coroutineDispatchers: CoroutineDispatchers,
|
||||
) {
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(coroutineScope: CoroutineScope): RoomSelectSearchDataSource
|
||||
}
|
||||
|
||||
private val roomList = roomListService.createRoomList(
|
||||
pageSize = PAGE_SIZE,
|
||||
initialFilter = RoomListFilter.all(),
|
||||
source = RoomList.Source.All,
|
||||
)
|
||||
coroutineScope = coroutineScope
|
||||
).apply {
|
||||
loadAllIncrementally(coroutineScope)
|
||||
}
|
||||
|
||||
val roomInfoList: Flow<ImmutableList<SelectRoomInfo>> = roomList.filteredSummaries
|
||||
.map { roomSummaries ->
|
||||
@@ -51,10 +63,6 @@ class RoomSelectSearchDataSource(
|
||||
}
|
||||
.flowOn(coroutineDispatchers.computation)
|
||||
|
||||
suspend fun load() = coroutineScope {
|
||||
roomList.loadAllIncrementally(this)
|
||||
}
|
||||
|
||||
suspend fun setSearchQuery(searchQuery: String) = coroutineScope {
|
||||
val filter = if (searchQuery.isBlank()) {
|
||||
RoomListFilter.all()
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package io.element.android.libraries.roomselect.impl
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
@@ -16,14 +17,18 @@ import io.element.android.libraries.roomselect.api.RoomSelectEntryPoint
|
||||
import io.element.android.libraries.roomselect.api.RoomSelectMode
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.node.TestParentNode
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class DefaultRoomSelectEntryPointTest {
|
||||
@get:Rule
|
||||
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun `test node builder`() = runTest {
|
||||
val entryPoint = DefaultRoomSelectEntryPoint()
|
||||
|
||||
@@ -22,6 +22,7 @@ import io.element.android.libraries.roomselect.api.RoomSelectMode
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
@@ -119,8 +120,13 @@ internal fun TestScope.createRoomSelectPresenter(
|
||||
roomListService: RoomListService = FakeRoomListService(),
|
||||
) = RoomSelectPresenter(
|
||||
mode = mode,
|
||||
dataSource = RoomSelectSearchDataSource(
|
||||
roomListService = roomListService,
|
||||
coroutineDispatchers = testCoroutineDispatchers(),
|
||||
),
|
||||
dataSourceFactory = object : RoomSelectSearchDataSource.Factory {
|
||||
override fun create(coroutineScope: CoroutineScope): RoomSelectSearchDataSource {
|
||||
return RoomSelectSearchDataSource(
|
||||
coroutineScope = coroutineScope,
|
||||
roomListService = roomListService,
|
||||
coroutineDispatchers = testCoroutineDispatchers(),
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user