sdk : allow passing coroutineScope to RoomList

This commit is contained in:
ganfra
2026-01-21 15:44:37 +01:00
parent 941340f250
commit edba196a69
15 changed files with 83 additions and 35 deletions

View File

@@ -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,

View File

@@ -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)

View File

@@ -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()

View File

@@ -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()

View File

@@ -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(),
)
}
}
)