From 250667b5b59ab203c4ce14b2710808e61016bbaa Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 1 Oct 2025 10:23:10 +0200 Subject: [PATCH 1/3] di : clean some code --- ...ltRoomComponentFactory.kt => DefaultRoomGraphFactory.kt} | 6 +++--- app/src/main/kotlin/io/element/android/x/di/RoomGraph.kt | 3 --- app/src/main/kotlin/io/element/android/x/di/SessionGraph.kt | 3 --- .../di/{RoomComponentFactory.kt => RoomGraphFactory.kt} | 2 +- .../android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt | 6 +++--- .../element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt | 6 +++--- .../impl/ChangeRoomMemberRolesRootNode.kt | 6 +++--- .../impl/DefaultChangeRoomMemberRolesEntyPointTest.kt | 2 +- 8 files changed, 14 insertions(+), 20 deletions(-) rename app/src/main/kotlin/io/element/android/x/di/{DefaultRoomComponentFactory.kt => DefaultRoomGraphFactory.kt} (84%) rename appnav/src/main/kotlin/io/element/android/appnav/di/{RoomComponentFactory.kt => RoomGraphFactory.kt} (90%) diff --git a/app/src/main/kotlin/io/element/android/x/di/DefaultRoomComponentFactory.kt b/app/src/main/kotlin/io/element/android/x/di/DefaultRoomGraphFactory.kt similarity index 84% rename from app/src/main/kotlin/io/element/android/x/di/DefaultRoomComponentFactory.kt rename to app/src/main/kotlin/io/element/android/x/di/DefaultRoomGraphFactory.kt index 8bba1dd50b..9ae8c54eb7 100644 --- a/app/src/main/kotlin/io/element/android/x/di/DefaultRoomComponentFactory.kt +++ b/app/src/main/kotlin/io/element/android/x/di/DefaultRoomGraphFactory.kt @@ -9,15 +9,15 @@ package io.element.android.x.di import dev.zacsweers.metro.ContributesBinding import dev.zacsweers.metro.Inject -import io.element.android.appnav.di.RoomComponentFactory +import io.element.android.appnav.di.RoomGraphFactory import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.room.JoinedRoom @ContributesBinding(SessionScope::class) @Inject -class DefaultRoomComponentFactory( +class DefaultRoomGraphFactory( private val sessionGraph: SessionGraph, -) : RoomComponentFactory { +) : RoomGraphFactory { override fun create(room: JoinedRoom): Any { return sessionGraph.roomGraphFactory .create(room, room) diff --git a/app/src/main/kotlin/io/element/android/x/di/RoomGraph.kt b/app/src/main/kotlin/io/element/android/x/di/RoomGraph.kt index e452bc2a9f..e48dd52daf 100644 --- a/app/src/main/kotlin/io/element/android/x/di/RoomGraph.kt +++ b/app/src/main/kotlin/io/element/android/x/di/RoomGraph.kt @@ -7,18 +7,15 @@ package io.element.android.x.di -import dev.zacsweers.metro.ContributesTo import dev.zacsweers.metro.GraphExtension import dev.zacsweers.metro.Provides import io.element.android.libraries.architecture.NodeFactoriesBindings import io.element.android.libraries.di.RoomScope -import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.JoinedRoom @GraphExtension(RoomScope::class) interface RoomGraph : NodeFactoriesBindings { - @ContributesTo(SessionScope::class) @GraphExtension.Factory interface Factory { fun create( diff --git a/app/src/main/kotlin/io/element/android/x/di/SessionGraph.kt b/app/src/main/kotlin/io/element/android/x/di/SessionGraph.kt index 255c6c7ab9..3782b00a58 100644 --- a/app/src/main/kotlin/io/element/android/x/di/SessionGraph.kt +++ b/app/src/main/kotlin/io/element/android/x/di/SessionGraph.kt @@ -7,8 +7,6 @@ package io.element.android.x.di -import dev.zacsweers.metro.AppScope -import dev.zacsweers.metro.ContributesTo import dev.zacsweers.metro.GraphExtension import dev.zacsweers.metro.Provides import io.element.android.libraries.architecture.NodeFactoriesBindings @@ -19,7 +17,6 @@ import io.element.android.libraries.matrix.api.MatrixClient interface SessionGraph : NodeFactoriesBindings { val roomGraphFactory: RoomGraph.Factory - @ContributesTo(AppScope::class) @GraphExtension.Factory interface Factory { fun create(@Provides matrixClient: MatrixClient): SessionGraph diff --git a/appnav/src/main/kotlin/io/element/android/appnav/di/RoomComponentFactory.kt b/appnav/src/main/kotlin/io/element/android/appnav/di/RoomGraphFactory.kt similarity index 90% rename from appnav/src/main/kotlin/io/element/android/appnav/di/RoomComponentFactory.kt rename to appnav/src/main/kotlin/io/element/android/appnav/di/RoomGraphFactory.kt index fc8f2c175b..ae0a3a81f2 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/di/RoomComponentFactory.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/di/RoomGraphFactory.kt @@ -9,6 +9,6 @@ package io.element.android.appnav.di import io.element.android.libraries.matrix.api.room.JoinedRoom -fun interface RoomComponentFactory { +fun interface RoomGraphFactory { fun create(room: JoinedRoom): Any } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt index 9ff05ac49a..f0f8dff3e7 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt @@ -20,7 +20,7 @@ import com.bumble.appyx.navmodel.backstack.operation.push import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode -import io.element.android.appnav.di.RoomComponentFactory +import io.element.android.appnav.di.RoomGraphFactory import io.element.android.appnav.room.RoomNavigationTarget import io.element.android.features.messages.api.MessagesEntryPoint import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint @@ -56,7 +56,7 @@ class JoinedRoomLoadedFlowNode( private val sessionCoroutineScope: CoroutineScope, private val matrixClient: MatrixClient, private val activeRoomsHolder: ActiveRoomsHolder, - roomComponentFactory: RoomComponentFactory, + roomGraphFactory: RoomGraphFactory, ) : BaseFlowNode( backstack = BackStack( initialElement = when (val input = plugins.filterIsInstance().first().initialElement) { @@ -83,7 +83,7 @@ class JoinedRoomLoadedFlowNode( private val inputs: Inputs = inputs() private val callbacks = plugins.filterIsInstance() - override val graph = roomComponentFactory.create(inputs.room) + override val graph = roomGraphFactory.create(inputs.room) init { lifecycle.subscribe( diff --git a/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt index bbaa196520..dfb2638dc1 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt @@ -17,7 +17,7 @@ import com.bumble.appyx.navmodel.backstack.activeElement import com.bumble.appyx.testing.junit4.util.MainDispatcherRule import com.bumble.appyx.testing.unit.common.helper.parentNodeTestHelper import com.google.common.truth.Truth.assertThat -import io.element.android.appnav.di.RoomComponentFactory +import io.element.android.appnav.di.RoomGraphFactory import io.element.android.appnav.room.RoomNavigationTarget import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode import io.element.android.features.messages.api.MessagesEntryPoint @@ -70,7 +70,7 @@ class JoinedRoomLoadedFlowNodeTest { } } - private class FakeRoomComponentFactory : RoomComponentFactory { + private class FakeRoomGraphFactory : RoomGraphFactory { override fun create(room: JoinedRoom): Any { return Unit } @@ -110,7 +110,7 @@ class JoinedRoomLoadedFlowNodeTest { roomDetailsEntryPoint = roomDetailsEntryPoint, appNavigationStateService = FakeAppNavigationStateService(), sessionCoroutineScope = this, - roomComponentFactory = FakeRoomComponentFactory(), + roomGraphFactory = FakeRoomGraphFactory(), matrixClient = FakeMatrixClient(), activeRoomsHolder = activeRoomsHolder, ) diff --git a/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRoomMemberRolesRootNode.kt b/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRoomMemberRolesRootNode.kt index 8467ef7bcb..2c3f77f208 100644 --- a/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRoomMemberRolesRootNode.kt +++ b/features/changeroommemberroles/impl/src/main/kotlin/io/element/android/features/changeroommemberroles/impl/ChangeRoomMemberRolesRootNode.kt @@ -19,7 +19,7 @@ import com.bumble.appyx.core.plugin.Plugin import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode -import io.element.android.appnav.di.RoomComponentFactory +import io.element.android.appnav.di.RoomGraphFactory import io.element.android.features.changeroommemberroes.api.ChangeRoomMemberRolesEntryPoint import io.element.android.features.changeroommemberroes.api.ChangeRoomMemberRolesListType import io.element.android.libraries.architecture.NodeInputs @@ -36,7 +36,7 @@ import kotlinx.parcelize.Parcelize class ChangeRoomMemberRolesRootNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, - roomComponentFactory: RoomComponentFactory, + roomGraphFactory: RoomGraphFactory, ) : ParentNode( navModel = PermanentNavModel( navTargets = setOf(NavTarget), @@ -54,7 +54,7 @@ class ChangeRoomMemberRolesRootNode( private val inputs = inputs() - override val graph = roomComponentFactory.create(inputs.joinedRoom) + override val graph = roomGraphFactory.create(inputs.joinedRoom) override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { return createNode( diff --git a/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/DefaultChangeRoomMemberRolesEntyPointTest.kt b/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/DefaultChangeRoomMemberRolesEntyPointTest.kt index 5f68fe5970..621af8edaf 100644 --- a/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/DefaultChangeRoomMemberRolesEntyPointTest.kt +++ b/features/changeroommemberroles/impl/src/test/kotlin/io/element/android/features/changeroommemberroles/impl/DefaultChangeRoomMemberRolesEntyPointTest.kt @@ -26,7 +26,7 @@ class DefaultChangeRoomMemberRolesEntyPointTest { ChangeRoomMemberRolesRootNode( buildContext = buildContext, plugins = plugins, - roomComponentFactory = { }, + roomGraphFactory = { }, ) } val room = FakeJoinedRoom() From 388cb317005b8ef5d29edc89e441605b38b00e86 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 1 Oct 2025 10:49:35 +0200 Subject: [PATCH 2/3] misc (space) : ensure SpaceRoomList is destroyed --- .../features/space/impl/SpaceFlowNode.kt | 19 ++++++- .../features/space/impl/di/SpaceFlowGraph.kt | 24 +++++++++ .../features/space/impl/di/SpaceFlowScope.kt | 10 ++++ .../space/impl/leave/LeaveSpaceNode.kt | 11 ++--- .../space/impl/leave/LeaveSpacePresenter.kt | 19 ++----- .../features/space/impl/root/SpaceNode.kt | 15 +++--- .../space/impl/root/SpacePresenter.kt | 16 ++---- .../matrix/api/spaces/SpaceRoomList.kt | 5 ++ .../matrix/impl/spaces/RustSpaceRoomList.kt | 49 ++++++++++++------- .../matrix/impl/spaces/RustSpaceService.kt | 5 +- .../impl/spaces/RustSpaceRoomListTest.kt | 6 ++- .../matrix/test/spaces/FakeSpaceRoomList.kt | 7 +++ 12 files changed, 120 insertions(+), 66 deletions(-) create mode 100644 features/space/impl/src/main/kotlin/io/element/android/features/space/impl/di/SpaceFlowGraph.kt create mode 100644 features/space/impl/src/main/kotlin/io/element/android/features/space/impl/di/SpaceFlowScope.kt diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceFlowNode.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceFlowNode.kt index 3515e07a77..fffdeb6246 100644 --- a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceFlowNode.kt +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/SpaceFlowNode.kt @@ -13,6 +13,7 @@ import android.os.Parcelable import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin @@ -22,13 +23,16 @@ import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode import io.element.android.features.space.api.SpaceEntryPoint +import io.element.android.features.space.impl.di.SpaceFlowGraph import io.element.android.features.space.impl.leave.LeaveSpaceNode import io.element.android.features.space.impl.root.SpaceNode import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.inputs +import io.element.android.libraries.di.DependencyInjectionGraphOwner import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId import kotlinx.parcelize.Parcelize @@ -37,6 +41,8 @@ import kotlinx.parcelize.Parcelize class SpaceFlowNode( @Assisted val buildContext: BuildContext, @Assisted plugins: List, + matrixClient: MatrixClient, + graphFactory: SpaceFlowGraph.Factory, ) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Root, @@ -44,9 +50,11 @@ class SpaceFlowNode( ), buildContext = buildContext, plugins = plugins, -) { +), DependencyInjectionGraphOwner { private val inputs: SpaceEntryPoint.Inputs = inputs() private val callback = plugins.filterIsInstance().single() + private val spaceRoomList = matrixClient.spaceService.spaceRoomList(inputs.roomId) + override val graph = graphFactory.create(spaceRoomList) sealed interface NavTarget : Parcelable { @Parcelize @@ -56,6 +64,15 @@ class SpaceFlowNode( data object Leave : NavTarget } + override fun onBuilt() { + super.onBuilt() + lifecycle.subscribe( + onDestroy = { + spaceRoomList.destroy() + } + ) + } + override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { return when (navTarget) { NavTarget.Leave -> { diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/di/SpaceFlowGraph.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/di/SpaceFlowGraph.kt new file mode 100644 index 0000000000..b1dac522b4 --- /dev/null +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/di/SpaceFlowGraph.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.space.impl.di + +import dev.zacsweers.metro.ContributesTo +import dev.zacsweers.metro.GraphExtension +import dev.zacsweers.metro.Provides +import io.element.android.libraries.architecture.NodeFactoriesBindings +import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.spaces.SpaceRoomList + +@GraphExtension(SpaceFlowScope::class) +interface SpaceFlowGraph : NodeFactoriesBindings { + @ContributesTo(SessionScope::class) + @GraphExtension.Factory + interface Factory { + fun create(@Provides spaceRoomList: SpaceRoomList): SpaceFlowGraph + } +} diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/di/SpaceFlowScope.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/di/SpaceFlowScope.kt new file mode 100644 index 0000000000..77fb07f871 --- /dev/null +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/di/SpaceFlowScope.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.space.impl.di + +abstract class SpaceFlowScope private constructor() diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpaceNode.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpaceNode.kt index 0973092994..df313481a1 100644 --- a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpaceNode.kt +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpaceNode.kt @@ -15,20 +15,15 @@ import com.bumble.appyx.core.plugin.Plugin import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode -import io.element.android.features.space.api.SpaceEntryPoint -import io.element.android.libraries.architecture.inputs -import io.element.android.libraries.di.SessionScope +import io.element.android.features.space.impl.di.SpaceFlowScope -@ContributesNode(SessionScope::class) +@ContributesNode(SpaceFlowScope::class) @AssistedInject class LeaveSpaceNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, - presenterFactory: LeaveSpacePresenter.Factory, + private val presenter: LeaveSpacePresenter, ) : Node(buildContext, plugins = plugins) { - private val inputs: SpaceEntryPoint.Inputs = inputs() - private val presenter = presenterFactory.create(inputs) - @Composable override fun View(modifier: Modifier) { val state = presenter.present() diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpacePresenter.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpacePresenter.kt index 9da27e244d..7af18c1b6d 100644 --- a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpacePresenter.kt +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpacePresenter.kt @@ -15,17 +15,14 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import dev.zacsweers.metro.Assisted -import dev.zacsweers.metro.AssistedFactory -import dev.zacsweers.metro.AssistedInject -import io.element.android.features.space.api.SpaceEntryPoint +import dev.zacsweers.metro.Inject import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runUpdatingState -import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.spaces.SpaceRoom +import io.element.android.libraries.matrix.api.spaces.SpaceRoomList import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentSetOf @@ -35,18 +32,10 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import kotlin.jvm.optionals.getOrNull -@AssistedInject +@Inject class LeaveSpacePresenter( - @Assisted private val inputs: SpaceEntryPoint.Inputs, - matrixClient: MatrixClient, + private val spaceRoomList: SpaceRoomList, ) : Presenter { - @AssistedFactory - fun interface Factory { - fun create(inputs: SpaceEntryPoint.Inputs): LeaveSpacePresenter - } - - private val spaceRoomList = matrixClient.spaceService.spaceRoomList(inputs.roomId) - @Composable override fun present(): LeaveSpaceState { val coroutineScope = rememberCoroutineScope() diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceNode.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceNode.kt index 768bd9c795..d63f031222 100644 --- a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceNode.kt +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceNode.kt @@ -18,36 +18,33 @@ import com.bumble.appyx.core.plugin.Plugin import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode -import io.element.android.features.space.api.SpaceEntryPoint +import io.element.android.features.space.impl.di.SpaceFlowScope import io.element.android.libraries.androidutils.R import io.element.android.libraries.androidutils.system.startSharePlainTextIntent -import io.element.android.libraries.architecture.inputs -import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.spaces.SpaceRoomList import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.coroutines.launch import timber.log.Timber -@ContributesNode(SessionScope::class) +@ContributesNode(SpaceFlowScope::class) @AssistedInject class SpaceNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, - presenterFactory: SpacePresenter.Factory, + private val presenter: SpacePresenter, private val matrixClient: MatrixClient, + private val spaceRoomList: SpaceRoomList, ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { fun onOpenRoom(roomId: RoomId, viaParameters: List) fun onLeaveSpace() } - - private val inputs: SpaceEntryPoint.Inputs = inputs() private val callback = plugins.filterIsInstance().single() - private val presenter = presenterFactory.create(inputs) private fun onShareRoom(context: Context) = lifecycleScope.launch { - matrixClient.getRoom(inputs.roomId)?.use { room -> + matrixClient.getRoom(spaceRoomList.roomId)?.use { room -> room.getPermalink() .onSuccess { permalink -> context.startSharePlainTextIntent( diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpacePresenter.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpacePresenter.kt index 3d4bcc8fdd..e0a31bac5a 100644 --- a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpacePresenter.kt +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpacePresenter.kt @@ -13,11 +13,8 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import dev.zacsweers.metro.Assisted -import dev.zacsweers.metro.AssistedFactory -import dev.zacsweers.metro.AssistedInject +import dev.zacsweers.metro.Inject import io.element.android.features.invite.api.SeenInvitesStore -import io.element.android.features.space.api.SpaceEntryPoint import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.coroutine.mapState import io.element.android.libraries.matrix.api.MatrixClient @@ -31,19 +28,12 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlin.jvm.optionals.getOrNull -@AssistedInject +@Inject class SpacePresenter( - @Assisted private val inputs: SpaceEntryPoint.Inputs, + private val spaceRoomList: SpaceRoomList, private val client: MatrixClient, private val seenInvitesStore: SeenInvitesStore, ) : Presenter { - @AssistedFactory - fun interface Factory { - fun create(inputs: SpaceEntryPoint.Inputs): SpacePresenter - } - - private val spaceRoomList = client.spaceService.spaceRoomList(inputs.roomId) - @Composable override fun present(): SpaceState { LaunchedEffect(Unit) { diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceRoomList.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceRoomList.kt index 060eb1f2db..1dddfadc5b 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceRoomList.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/spaces/SpaceRoomList.kt @@ -7,6 +7,7 @@ package io.element.android.libraries.matrix.api.spaces +import io.element.android.libraries.matrix.api.core.RoomId import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import java.util.Optional @@ -17,9 +18,13 @@ interface SpaceRoomList { data class Idle(val hasMoreToLoad: Boolean) : PaginationStatus } + val roomId: RoomId + val currentSpaceFlow: StateFlow> val spaceRoomsFlow: Flow> val paginationStatusFlow: StateFlow suspend fun paginate(): Result + + fun destroy() } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceRoomList.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceRoomList.kt index dbcab85ab1..b94c3ffd1b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceRoomList.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceRoomList.kt @@ -8,26 +8,31 @@ package io.element.android.libraries.matrix.impl.spaces import io.element.android.libraries.core.extensions.runCatchingExceptions +import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.spaces.SpaceRoom import io.element.android.libraries.matrix.api.spaces.SpaceRoomList import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import timber.log.Timber import uniffi.matrix_sdk_ui.SpaceRoomListPaginationState import java.util.Optional import org.matrix.rustcomponents.sdk.SpaceRoomList as InnerSpaceRoomList class RustSpaceRoomList( + override val roomId: RoomId, private val innerProvider: suspend () -> InnerSpaceRoomList, - sessionCoroutineScope: CoroutineScope, + private val coroutineScope: CoroutineScope, spaceRoomMapper: SpaceRoomMapper, ) : SpaceRoomList { - private val inner = CompletableDeferred() + private val innerCompletable = CompletableDeferred() override val currentSpaceFlow = MutableStateFlow>(Optional.empty()) @@ -41,37 +46,45 @@ class RustSpaceRoomList( ) init { - sessionCoroutineScope.launch { - inner.complete(innerProvider()) - } - sessionCoroutineScope.launch { - inner.await().paginationStateFlow() + coroutineScope.launch { + val inner = innerProvider() + innerCompletable.complete(inner) + + inner.paginationStateFlow() .onEach { paginationStatus -> paginationStatusFlow.emit(paginationStatus.into()) } - .collect() - } + .launchIn(this) - sessionCoroutineScope.launch { - inner.await().spaceListUpdateFlow() + inner.spaceListUpdateFlow() .onEach { updates -> spaceListUpdateProcessor.postUpdates(updates) } - .collect() - } - sessionCoroutineScope.launch { - inner.await().spaceUpdateFlow() + .launchIn(this) + + inner.spaceUpdateFlow() .map { space -> space.map(spaceRoomMapper::map) } .onEach { space -> currentSpaceFlow.emit(space) } - .collect() + .launchIn(this) } } override suspend fun paginate(): Result { return runCatchingExceptions { - inner.await().paginate() + innerCompletable.await().paginate() + } + } + + @OptIn(ExperimentalCoroutinesApi::class) + override fun destroy() { + Timber.d("Destroying SpaceRoomList $roomId") + coroutineScope.cancel() + try { + innerCompletable.getCompleted().destroy() + } catch (_: Exception) { + // Ignore, we just want to make sure it's completed } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceService.kt index 3dd905caf2..86d50a477c 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceService.kt @@ -7,6 +7,7 @@ package io.element.android.libraries.matrix.impl.spaces +import io.element.android.libraries.core.coroutine.childScope import io.element.android.libraries.core.extensions.runCatchingExceptions import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.spaces.SpaceRoom @@ -54,9 +55,11 @@ class RustSpaceService( } override fun spaceRoomList(id: RoomId): SpaceRoomList { + val childCoroutineScope = sessionCoroutineScope.childScope(sessionDispatcher, "SpaceRoomListScope-$this") return RustSpaceRoomList( + roomId = id, innerProvider = { innerSpaceService.spaceRoomList(id.value) }, - sessionCoroutineScope = sessionCoroutineScope, + coroutineScope = childCoroutineScope, spaceRoomMapper = spaceRoomMapper, ) } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceRoomListTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceRoomListTest.kt index 007b6a669f..7a494ae8c3 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceRoomListTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/spaces/RustSpaceRoomListTest.kt @@ -11,9 +11,11 @@ package io.element.android.libraries.matrix.impl.spaces import app.cash.turbine.test import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.spaces.SpaceRoomList import io.element.android.libraries.matrix.impl.fixtures.factories.aRustSpaceRoom import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiSpaceRoomList +import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID_2 import io.element.android.tests.testutils.lambda.lambdaRecorder import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -84,13 +86,15 @@ class RustSpaceRoomListTest { } private fun TestScope.createRustSpaceRoomList( + roomId: RoomId = A_ROOM_ID, innerSpaceRoomList: InnerSpaceRoomList = FakeFfiSpaceRoomList(), innerProvider: suspend () -> InnerSpaceRoomList = { innerSpaceRoomList }, spaceRoomMapper: SpaceRoomMapper = SpaceRoomMapper(), ): RustSpaceRoomList { return RustSpaceRoomList( + roomId = roomId, innerProvider = innerProvider, - sessionCoroutineScope = backgroundScope, + coroutineScope = backgroundScope, spaceRoomMapper = spaceRoomMapper, ) } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/spaces/FakeSpaceRoomList.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/spaces/FakeSpaceRoomList.kt index d86e178fa9..6eac3dd0f4 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/spaces/FakeSpaceRoomList.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/spaces/FakeSpaceRoomList.kt @@ -7,8 +7,10 @@ package io.element.android.libraries.matrix.test.spaces +import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.spaces.SpaceRoom import io.element.android.libraries.matrix.api.spaces.SpaceRoomList +import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.simulateLongTask import kotlinx.coroutines.flow.Flow @@ -18,6 +20,7 @@ import kotlinx.coroutines.flow.asStateFlow import java.util.Optional class FakeSpaceRoomList( + override val roomId: RoomId = A_ROOM_ID, initialSpaceFlowValue: SpaceRoom? = null, initialSpaceRoomsValue: List = emptyList(), initialSpaceRoomList: SpaceRoomList.PaginationStatus = SpaceRoomList.PaginationStatus.Loading, @@ -47,4 +50,8 @@ class FakeSpaceRoomList( override suspend fun paginate(): Result = simulateLongTask { paginateResult() } + + override fun destroy() { + // No op + } } From 0944ab0c281e485d3e07ae4af7f48d4702f30287 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 1 Oct 2025 11:52:41 +0200 Subject: [PATCH 3/3] misc (space) : update tests after rework --- .../space/impl/DefaultSpaceEntryPointTest.kt | 10 +++ .../space/impl/di/FakeSpaceFlowGraph.kt | 25 ++++++ .../impl/leave/LeaveSpacePresenterTest.kt | 28 ++---- .../space/impl/root/SpacePresenterTest.kt | 86 ++++++------------- 4 files changed, 65 insertions(+), 84 deletions(-) create mode 100644 features/space/impl/src/test/kotlin/io/element/android/features/space/impl/di/FakeSpaceFlowGraph.kt diff --git a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPointTest.kt b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPointTest.kt index 0410944dbb..007c28e3a6 100644 --- a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPointTest.kt +++ b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/DefaultSpaceEntryPointTest.kt @@ -12,8 +12,12 @@ import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.testing.junit4.util.MainDispatcherRule import com.google.common.truth.Truth.assertThat import io.element.android.features.space.api.SpaceEntryPoint +import io.element.android.features.space.impl.di.FakeSpaceFlowGraph import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.test.A_ROOM_ID +import io.element.android.libraries.matrix.test.FakeMatrixClient +import io.element.android.libraries.matrix.test.spaces.FakeSpaceRoomList +import io.element.android.libraries.matrix.test.spaces.FakeSpaceService import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.node.TestParentNode import org.junit.Rule @@ -34,6 +38,12 @@ class DefaultSpaceEntryPointTest { SpaceFlowNode( buildContext = buildContext, plugins = plugins, + matrixClient = FakeMatrixClient( + spaceService = FakeSpaceService( + spaceRoomListResult = { _: RoomId -> FakeSpaceRoomList(A_ROOM_ID) } + ) + ), + graphFactory = FakeSpaceFlowGraph.Factory ) } val callback = object : SpaceEntryPoint.Callback { diff --git a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/di/FakeSpaceFlowGraph.kt b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/di/FakeSpaceFlowGraph.kt new file mode 100644 index 0000000000..09263ff52d --- /dev/null +++ b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/di/FakeSpaceFlowGraph.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.space.impl.di + +import com.bumble.appyx.core.node.Node +import io.element.android.libraries.architecture.AssistedNodeFactory +import io.element.android.libraries.matrix.api.spaces.SpaceRoomList +import kotlin.reflect.KClass + +class FakeSpaceFlowGraph : SpaceFlowGraph { + object Factory : SpaceFlowGraph.Factory { + override fun create(spaceRoomList: SpaceRoomList): SpaceFlowGraph { + return FakeSpaceFlowGraph() + } + } + + override fun nodeFactories(): Map, AssistedNodeFactory<*>> { + return emptyMap() + } +} diff --git a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/leave/LeaveSpacePresenterTest.kt b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/leave/LeaveSpacePresenterTest.kt index 5129181306..ee8962a345 100644 --- a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/leave/LeaveSpacePresenterTest.kt +++ b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/leave/LeaveSpacePresenterTest.kt @@ -10,15 +10,11 @@ package io.element.android.features.space.impl.leave import com.google.common.truth.Truth.assertThat -import io.element.android.features.space.api.SpaceEntryPoint import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData -import io.element.android.libraries.matrix.api.MatrixClient -import io.element.android.libraries.matrix.test.A_ROOM_ID +import io.element.android.libraries.matrix.api.spaces.SpaceRoomList import io.element.android.libraries.matrix.test.A_SPACE_NAME -import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.spaces.FakeSpaceRoomList -import io.element.android.libraries.matrix.test.spaces.FakeSpaceService import io.element.android.libraries.previewutils.room.aSpaceRoom import io.element.android.tests.testutils.test import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -29,15 +25,7 @@ import org.junit.Test class LeaveSpacePresenterTest { @Test fun `present - initial state`() = runTest { - val presenter = createLeaveSpacePresenter( - matrixClient = FakeMatrixClient( - spaceService = FakeSpaceService( - spaceRoomListResult = { - FakeSpaceRoomList() - }, - ), - ), - ) + val presenter = createLeaveSpacePresenter() presenter.test { val state = awaitItem() assertThat(state.spaceName).isNull() @@ -51,11 +39,7 @@ class LeaveSpacePresenterTest { fun `present - current space name`() = runTest { val fakeSpaceRoomList = FakeSpaceRoomList() val presenter = createLeaveSpacePresenter( - matrixClient = FakeMatrixClient( - spaceService = FakeSpaceService( - spaceRoomListResult = { fakeSpaceRoomList }, - ), - ), + spaceRoomList = fakeSpaceRoomList, ) presenter.test { val state = awaitItem() @@ -71,12 +55,10 @@ class LeaveSpacePresenterTest { } private fun createLeaveSpacePresenter( - inputs: SpaceEntryPoint.Inputs = SpaceEntryPoint.Inputs(A_ROOM_ID), - matrixClient: MatrixClient = FakeMatrixClient(), + spaceRoomList: SpaceRoomList = FakeSpaceRoomList(), ): LeaveSpacePresenter { return LeaveSpacePresenter( - inputs = inputs, - matrixClient = matrixClient, + spaceRoomList = spaceRoomList, ) } } diff --git a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/root/SpacePresenterTest.kt b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/root/SpacePresenterTest.kt index 1f096ff2b6..ff4b87101b 100644 --- a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/root/SpacePresenterTest.kt +++ b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/root/SpacePresenterTest.kt @@ -12,13 +12,10 @@ package io.element.android.features.space.impl.root import com.google.common.truth.Truth.assertThat import io.element.android.features.invite.api.SeenInvitesStore import io.element.android.features.invite.test.InMemorySeenInvitesStore -import io.element.android.features.space.api.SpaceEntryPoint import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.spaces.SpaceRoomList -import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.spaces.FakeSpaceRoomList -import io.element.android.libraries.matrix.test.spaces.FakeSpaceService import io.element.android.libraries.previewutils.room.aSpaceRoom import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.test @@ -33,17 +30,8 @@ class SpacePresenterTest { val paginateResult = lambdaRecorder> { Result.success(Unit) } - val presenter = createSpacePresenter( - client = FakeMatrixClient( - spaceService = FakeSpaceService( - spaceRoomListResult = { - FakeSpaceRoomList( - paginateResult = paginateResult, - ) - }, - ), - ), - ) + val spaceRoomList = FakeSpaceRoomList(paginateResult = paginateResult) + val presenter = createSpacePresenter(spaceRoomList = spaceRoomList) presenter.test { val state = awaitItem() assertThat(state.currentSpace).isNull() @@ -61,17 +49,8 @@ class SpacePresenterTest { val paginateResult = lambdaRecorder> { Result.success(Unit) } - val presenter = createSpacePresenter( - client = FakeMatrixClient( - spaceService = FakeSpaceService( - spaceRoomListResult = { - FakeSpaceRoomList( - paginateResult = paginateResult, - ) - }, - ), - ), - ) + val spaceRoomList = FakeSpaceRoomList(paginateResult = paginateResult) + val presenter = createSpacePresenter(spaceRoomList = spaceRoomList) presenter.test { val state = awaitItem() advanceUntilIdle() @@ -84,25 +63,20 @@ class SpacePresenterTest { @Test fun `present - has more to load value`() = runTest { - val fakeSpaceRoomList = FakeSpaceRoomList( - paginateResult = { Result.success(Unit) }, - ) - val presenter = createSpacePresenter( - client = FakeMatrixClient( - spaceService = FakeSpaceService( - spaceRoomListResult = { fakeSpaceRoomList }, - ), - ), - ) + val paginateResult = lambdaRecorder> { + Result.success(Unit) + } + val spaceRoomList = FakeSpaceRoomList(paginateResult = paginateResult) + val presenter = createSpacePresenter(spaceRoomList = spaceRoomList) presenter.test { val state = awaitItem() advanceUntilIdle() assertThat(state.hasMoreToLoad).isTrue() - fakeSpaceRoomList.emitPaginationStatus( + spaceRoomList.emitPaginationStatus( SpaceRoomList.PaginationStatus.Idle(hasMoreToLoad = false) ) assertThat(awaitItem().hasMoreToLoad).isFalse() - fakeSpaceRoomList.emitPaginationStatus( + spaceRoomList.emitPaginationStatus( SpaceRoomList.PaginationStatus.Idle(hasMoreToLoad = true) ) assertThat(awaitItem().hasMoreToLoad).isTrue() @@ -111,56 +85,46 @@ class SpacePresenterTest { @Test fun `present - current space value`() = runTest { - val fakeSpaceRoomList = FakeSpaceRoomList( - paginateResult = { Result.success(Unit) }, - ) - val presenter = createSpacePresenter( - client = FakeMatrixClient( - spaceService = FakeSpaceService( - spaceRoomListResult = { fakeSpaceRoomList }, - ), - ), - ) + val paginateResult = lambdaRecorder> { + Result.success(Unit) + } + val spaceRoomList = FakeSpaceRoomList(paginateResult = paginateResult) + val presenter = createSpacePresenter(spaceRoomList = spaceRoomList) presenter.test { val state = awaitItem() advanceUntilIdle() assertThat(state.currentSpace).isNull() val aSpace = aSpaceRoom() - fakeSpaceRoomList.emitCurrentSpace(aSpace) + spaceRoomList.emitCurrentSpace(aSpace) assertThat(awaitItem().currentSpace).isEqualTo(aSpace) } } @Test fun `present - children value`() = runTest { - val fakeSpaceRoomList = FakeSpaceRoomList( - paginateResult = { Result.success(Unit) }, - ) - val presenter = createSpacePresenter( - client = FakeMatrixClient( - spaceService = FakeSpaceService( - spaceRoomListResult = { fakeSpaceRoomList }, - ), - ), - ) + val paginateResult = lambdaRecorder> { + Result.success(Unit) + } + val spaceRoomList = FakeSpaceRoomList(paginateResult = paginateResult) + val presenter = createSpacePresenter(spaceRoomList = spaceRoomList) presenter.test { val state = awaitItem() advanceUntilIdle() assertThat(state.children).isEmpty() val aSpace = aSpaceRoom() - fakeSpaceRoomList.emitSpaceRooms(listOf(aSpace)) + spaceRoomList.emitSpaceRooms(listOf(aSpace)) assertThat(awaitItem().children).containsExactly(aSpace) } } private fun createSpacePresenter( - inputs: SpaceEntryPoint.Inputs = SpaceEntryPoint.Inputs(A_ROOM_ID), client: MatrixClient = FakeMatrixClient(), + spaceRoomList: SpaceRoomList = FakeSpaceRoomList(), seenInvitesStore: SeenInvitesStore = InMemorySeenInvitesStore(), ): SpacePresenter { return SpacePresenter( - inputs = inputs, client = client, + spaceRoomList = spaceRoomList, seenInvitesStore = seenInvitesStore, ) }