From 0f94ebc56e53f324c328dbc8d24f646e91bcb8cf Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Oct 2025 17:57:13 +0200 Subject: [PATCH 1/3] We do not need CurrentSessionIdHolder anymore. The SessionId can be provided by SessionMatrixModule and injected in constructors directly. --- .../event/TimelineItemContentFactory.kt | 6 +++--- .../fixtures/TimelineItemsFactoryFixtures.kt | 3 +-- .../userprofile/impl/UserProfileFlowNode.kt | 8 ++++---- .../impl/DefaultUserProfileEntryPointTest.kt | 5 ++--- .../matrix/api/user/CurrentSessionIdHolder.kt | 19 ------------------- .../matrix/impl/di/SessionMatrixModule.kt | 6 ++++++ .../impl/store/SessionPreferencesModule.kt | 6 +++--- 7 files changed, 19 insertions(+), 34 deletions(-) delete mode 100644 libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/CurrentSessionIdHolder.kt diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt index 8047acd09a..4f1c9ba90a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt @@ -13,6 +13,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.timeline.item.event.CallNotifyContent import io.element.android.libraries.matrix.api.timeline.item.event.EventContent @@ -31,7 +32,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.StickerConten import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName -import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder @Inject class TimelineItemContentFactory( @@ -45,7 +45,7 @@ class TimelineItemContentFactory( private val stateFactory: TimelineItemContentStateFactory, private val failedToParseMessageFactory: TimelineItemContentFailedToParseMessageFactory, private val failedToParseStateFactory: TimelineItemContentFailedToParseStateFactory, - private val currentSessionIdHolder: CurrentSessionIdHolder, + private val sessionId: SessionId, ) { suspend fun create(eventTimelineItem: EventTimelineItem): TimelineItemEventContent { return create( @@ -64,7 +64,7 @@ class TimelineItemContentFactory( sender: UserId, senderProfile: ProfileTimelineDetails, ): TimelineItemEventContent { - val isOutgoing = currentSessionIdHolder.current == sender + val isOutgoing = sessionId == sender return when (itemContent) { is FailedToParseMessageLikeContent -> failedToParseMessageFactory.create(itemContent) is FailedToParseStateContent -> failedToParseStateFactory.create(itemContent) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/TimelineItemsFactoryFixtures.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/TimelineItemsFactoryFixtures.kt index 502ab74062..539618df9f 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/TimelineItemsFactoryFixtures.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/TimelineItemsFactoryFixtures.kt @@ -33,7 +33,6 @@ import io.element.android.libraries.dateformatter.test.FakeDateFormatter import io.element.android.libraries.eventformatter.api.TimelineEventFormatter import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.timeline.item.event.EventContent -import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation @@ -78,7 +77,7 @@ internal fun TestScope.aTimelineItemsFactory( stateFactory = TimelineItemContentStateFactory(timelineEventFormatter), failedToParseMessageFactory = TimelineItemContentFailedToParseMessageFactory(), failedToParseStateFactory = TimelineItemContentFailedToParseStateFactory(), - currentSessionIdHolder = CurrentSessionIdHolder(matrixClient), + sessionId = matrixClient.sessionId, ), matrixClient = matrixClient, dateFormatter = FakeDateFormatter(), diff --git a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/UserProfileFlowNode.kt b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/UserProfileFlowNode.kt index e0aac27f6a..5828d60c25 100644 --- a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/UserProfileFlowNode.kt +++ b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/UserProfileFlowNode.kt @@ -33,8 +33,8 @@ import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder import io.element.android.libraries.matrix.api.verification.VerificationRequest import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import kotlinx.parcelize.Parcelize @@ -45,7 +45,7 @@ class UserProfileFlowNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val elementCallEntryPoint: ElementCallEntryPoint, - private val sessionIdHolder: CurrentSessionIdHolder, + private val sessionId: SessionId, private val mediaViewerEntryPoint: MediaViewerEntryPoint, private val outgoingVerificationEntryPoint: OutgoingVerificationEntryPoint, ) : BaseFlowNode( @@ -82,7 +82,7 @@ class UserProfileFlowNode( } override fun onStartCall(dmRoomId: RoomId) { - elementCallEntryPoint.startCall(CallType.RoomCall(sessionId = sessionIdHolder.current, roomId = dmRoomId)) + elementCallEntryPoint.startCall(CallType.RoomCall(sessionId = sessionId, roomId = dmRoomId)) } override fun onVerifyUser(userId: UserId) { @@ -99,7 +99,7 @@ class UserProfileFlowNode( } override fun onViewInTimeline(eventId: EventId) { - // Cannot happen + // Cannot happen } } mediaViewerEntryPoint.nodeBuilder(this, buildContext) diff --git a/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/DefaultUserProfileEntryPointTest.kt b/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/DefaultUserProfileEntryPointTest.kt index 1537167d20..75bc434048 100644 --- a/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/DefaultUserProfileEntryPointTest.kt +++ b/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/DefaultUserProfileEntryPointTest.kt @@ -19,9 +19,8 @@ import io.element.android.features.verifysession.api.OutgoingVerificationEntryPo import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder +import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_USER_ID -import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.node.TestParentNode @@ -43,7 +42,7 @@ class DefaultUserProfileEntryPointTest { UserProfileFlowNode( buildContext = buildContext, plugins = plugins, - sessionIdHolder = CurrentSessionIdHolder(FakeMatrixClient()), + sessionId = A_SESSION_ID, elementCallEntryPoint = object : ElementCallEntryPoint { override fun startCall(callType: CallType) = lambdaError() override suspend fun handleIncomingCall( diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/CurrentSessionIdHolder.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/CurrentSessionIdHolder.kt deleted file mode 100644 index 171f8337e0..0000000000 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/CurrentSessionIdHolder.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2023, 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.libraries.matrix.api.user - -import dev.zacsweers.metro.Inject -import dev.zacsweers.metro.SingleIn -import io.element.android.libraries.di.SessionScope -import io.element.android.libraries.matrix.api.MatrixClient - -@SingleIn(SessionScope::class) -@Inject -class CurrentSessionIdHolder(matrixClient: MatrixClient) { - val current = matrixClient.sessionId -} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/di/SessionMatrixModule.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/di/SessionMatrixModule.kt index ef24cbba1a..4d1f244bd2 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/di/SessionMatrixModule.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/di/SessionMatrixModule.kt @@ -13,6 +13,7 @@ import dev.zacsweers.metro.Provides import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MediaPreviewService @@ -27,6 +28,11 @@ import kotlinx.coroutines.CoroutineScope @BindingContainer @ContributesTo(SessionScope::class) object SessionMatrixModule { + @Provides + fun providesSessionId(matrixClient: MatrixClient): SessionId { + return matrixClient.sessionId + } + @Provides fun providesSessionVerificationService(matrixClient: MatrixClient): SessionVerificationService { return matrixClient.sessionVerificationService() diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/SessionPreferencesModule.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/SessionPreferencesModule.kt index d9621cd6e0..225ea4e3d2 100644 --- a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/SessionPreferencesModule.kt +++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/SessionPreferencesModule.kt @@ -12,7 +12,7 @@ import dev.zacsweers.metro.ContributesTo import dev.zacsweers.metro.Provides import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.annotations.SessionCoroutineScope -import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder +import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.preferences.api.store.SessionPreferencesStore import kotlinx.coroutines.CoroutineScope @@ -22,10 +22,10 @@ object SessionPreferencesModule { @Provides fun providesSessionPreferencesStore( defaultSessionPreferencesStoreFactory: DefaultSessionPreferencesStoreFactory, - currentSessionIdHolder: CurrentSessionIdHolder, + sessionId: SessionId, @SessionCoroutineScope sessionCoroutineScope: CoroutineScope, ): SessionPreferencesStore { return defaultSessionPreferencesStoreFactory - .get(currentSessionIdHolder.current, sessionCoroutineScope) + .get(sessionId, sessionCoroutineScope) } } From ad9a6fec6f2c48f40efac887c6801a8fda098755 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Oct 2025 09:37:56 +0200 Subject: [PATCH 2/3] Improve SignedOutPresenter. We can now provide a SessionId in the Factory. --- .../features/signedout/impl/SignedOutNode.kt | 2 +- .../signedout/impl/SignedOutPresenter.kt | 19 +++++++++---------- .../signedout/impl/SignedOutPresenterTest.kt | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutNode.kt b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutNode.kt index 1a9505282e..1bacc78932 100644 --- a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutNode.kt +++ b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutNode.kt @@ -32,7 +32,7 @@ class SignedOutNode( ) : NodeInputs private val inputs: Inputs = inputs() - private val presenter = presenterFactory.create(inputs.sessionId.value) + private val presenter = presenterFactory.create(inputs.sessionId) @Composable override fun View(modifier: Modifier) { diff --git a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutPresenter.kt b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutPresenter.kt index 4680b4c7ec..7c9d1e6d83 100644 --- a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutPresenter.kt +++ b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutPresenter.kt @@ -9,7 +9,6 @@ package io.element.android.features.signedout.impl import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -18,35 +17,35 @@ import dev.zacsweers.metro.AssistedFactory import dev.zacsweers.metro.AssistedInject import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.meta.BuildMeta +import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.sessionstorage.api.SessionStore +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch @AssistedInject class SignedOutPresenter( - // Cannot inject SessionId - @Assisted private val sessionId: String, + @Assisted private val sessionId: SessionId, private val sessionStore: SessionStore, private val buildMeta: BuildMeta, ) : Presenter { @AssistedFactory fun interface Factory { - fun create(sessionId: String): SignedOutPresenter + fun create(sessionId: SessionId): SignedOutPresenter } @Composable override fun present(): SignedOutState { - val sessions by remember { - sessionStore.sessionsFlow() - }.collectAsState(initial = emptyList()) val signedOutSession by remember { - derivedStateOf { sessions.firstOrNull { it.userId == sessionId } } - } + sessionStore.sessionsFlow().map { sessions -> + sessions.firstOrNull { it.userId == sessionId.value } + } + }.collectAsState(initial = null) val coroutineScope = rememberCoroutineScope() fun handleEvents(event: SignedOutEvents) { when (event) { SignedOutEvents.SignInAgain -> coroutineScope.launch { - sessionStore.removeSession(sessionId) + sessionStore.removeSession(sessionId.value) } } } diff --git a/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/SignedOutPresenterTest.kt b/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/SignedOutPresenterTest.kt index de5634f269..e53c0af112 100644 --- a/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/SignedOutPresenterTest.kt +++ b/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/SignedOutPresenterTest.kt @@ -70,7 +70,7 @@ internal fun createSignedOutPresenter( sessionStore: SessionStore = InMemorySessionStore(), ): SignedOutPresenter { return SignedOutPresenter( - sessionId = sessionId.value, + sessionId = sessionId, sessionStore = sessionStore, buildMeta = aBuildMeta(applicationName = AN_APPLICATION_NAME), ) From ed4d49d98d9aaf39edd799d1f94488c148869295 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Oct 2025 10:14:01 +0200 Subject: [PATCH 3/3] Fix test. --- .../features/signedout/impl/DefaultSignedOutEntryPointTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/DefaultSignedOutEntryPointTest.kt b/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/DefaultSignedOutEntryPointTest.kt index 860ad88d8a..6366ba5ea1 100644 --- a/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/DefaultSignedOutEntryPointTest.kt +++ b/features/signedout/impl/src/test/kotlin/io/element/android/features/signedout/impl/DefaultSignedOutEntryPointTest.kt @@ -28,7 +28,7 @@ class DefaultSignedOutEntryPointTest { buildContext = buildContext, plugins = plugins, presenterFactory = { sessionId -> - assertThat(sessionId).isEqualTo(A_SESSION_ID.value) + assertThat(sessionId).isEqualTo(A_SESSION_ID) createSignedOutPresenter() } )