From f9ba0819f2f1ff6ee3745819f8db99f05b4bb063 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 15:36:06 +0200 Subject: [PATCH 01/38] Add Konsist test on Immutable annotation --- .../preview/AttachmentsPreviewEvents.kt | 3 --- .../impl/messagecomposer/MessageComposerEvents.kt | 3 +-- .../android/tests/konsist/KonsistImmutableTest.kt | 14 ++++++++++++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewEvents.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewEvents.kt index e679a43da7..9cdd52c97f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewEvents.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewEvents.kt @@ -7,9 +7,6 @@ package io.element.android.features.messages.impl.attachments.preview -import androidx.compose.runtime.Immutable - -@Immutable sealed interface AttachmentsPreviewEvents { data object SendAttachment : AttachmentsPreviewEvents data object CancelAndDismiss : AttachmentsPreviewEvents diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerEvents.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerEvents.kt index bcbd575c73..0832303075 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerEvents.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerEvents.kt @@ -8,12 +8,10 @@ package io.element.android.features.messages.impl.messagecomposer import android.net.Uri -import androidx.compose.runtime.Immutable import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion import io.element.android.libraries.textcomposer.model.MessageComposerMode import io.element.android.libraries.textcomposer.model.Suggestion -@Immutable sealed interface MessageComposerEvents { data object ToggleFullScreenState : MessageComposerEvents data object SendMessage : MessageComposerEvents @@ -30,6 +28,7 @@ sealed interface MessageComposerEvents { data object Location : PickAttachmentSource data object Poll : PickAttachmentSource } + data class ToggleTextFormatting(val enabled: Boolean) : MessageComposerEvents data class Error(val error: Throwable) : MessageComposerEvents data class TypingNotice(val isTyping: Boolean) : MessageComposerEvents diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistImmutableTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistImmutableTest.kt index 0aa68503e5..c43a2ae741 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistImmutableTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistImmutableTest.kt @@ -7,8 +7,12 @@ package io.element.android.tests.konsist +import androidx.compose.runtime.Immutable import com.lemonappdev.konsist.api.Konsist +import com.lemonappdev.konsist.api.ext.list.withAnnotationOf +import com.lemonappdev.konsist.api.ext.list.withNameEndingWith import com.lemonappdev.konsist.api.ext.list.withoutName +import com.lemonappdev.konsist.api.verify.assertEmpty import com.lemonappdev.konsist.api.verify.assertFalse import org.junit.Test @@ -60,4 +64,14 @@ class KonsistImmutableTest { it.text.contains(".toPersistentMap()") } } + + @Test + fun `Immutable annotation is not used on sealed interface for Presenter Events`() { + Konsist + .scopeFromProduction() + .interfaces() + .withNameEndingWith("Events") + .withAnnotationOf(Immutable::class) + .assertEmpty() + } } From bc2b77d269a9c8d18d3eb5e4a45fec2aa240de75 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 16:33:42 +0200 Subject: [PATCH 02/38] Add a script to check stability of State classes tom script --- tools/compose/check_stability.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100755 tools/compose/check_stability.sh diff --git a/tools/compose/check_stability.sh b/tools/compose/check_stability.sh new file mode 100755 index 0000000000..c965c787cd --- /dev/null +++ b/tools/compose/check_stability.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# 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. + +set -e + +# Build the project with compose report +echo "Building the project with compose report..." +./gradlew assembleGplayDebug -PcomposeCompilerReports=true -PcomposeCompilerMetrics=true --stacktrace + +echo "Checking stability of State classes..." +# Using the find command, list all the files ending with -classes.txt +find . -type f -name "*-classes.txt" | while read -r file; do + # echo "Processing $file" + # Check that there is no line containing "unstable class .*State {" + if grep -E 'unstable class .*State \{' "$file"; then + echo "Found unstable State class in $file" + exit 1 + fi +done From 2109ad74b5332f4cae80e5531a8aad538f35e12b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 16:42:01 +0200 Subject: [PATCH 03/38] Add missing @Immutable annotation --- libraries/session-storage/api/build.gradle.kts | 2 +- .../android/libraries/sessionstorage/api/LoggedInState.kt | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/session-storage/api/build.gradle.kts b/libraries/session-storage/api/build.gradle.kts index 5a03e913b4..c98e2b88df 100644 --- a/libraries/session-storage/api/build.gradle.kts +++ b/libraries/session-storage/api/build.gradle.kts @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ plugins { - id("io.element.android-library") + id("io.element.android-compose-library") } android { diff --git a/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/LoggedInState.kt b/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/LoggedInState.kt index 71fdbe65e6..f4befd984f 100644 --- a/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/LoggedInState.kt +++ b/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/LoggedInState.kt @@ -7,6 +7,9 @@ package io.element.android.libraries.sessionstorage.api +import androidx.compose.runtime.Immutable + +@Immutable sealed interface LoggedInState { data object NotLoggedIn : LoggedInState data class LoggedIn( From e5781b280864d4702da90753a6b29de838dcfa0b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 16:45:36 +0200 Subject: [PATCH 04/38] Fix stability issue. --- .../android/features/home/impl/spaces/HomeSpacesPresenter.kt | 3 ++- .../android/features/home/impl/spaces/HomeSpacesState.kt | 3 ++- .../features/home/impl/spaces/HomeSpacesStateProvider.kt | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt index 8c3e2962ac..9486e6be62 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt @@ -17,6 +17,7 @@ import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.ui.safety.rememberHideInvitesAvatar import kotlinx.collections.immutable.persistentSetOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableSet import kotlinx.coroutines.flow.map @@ -39,7 +40,7 @@ class HomeSpacesPresenter( return HomeSpacesState( space = CurrentSpace.Root, - spaceRooms = spaceRooms, + spaceRooms = spaceRooms.toImmutableList(), seenSpaceInvites = seenSpaceInvites, hideInvitesAvatar = hideInvitesAvatar, eventSink = ::handleEvents, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesState.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesState.kt index 96733991f9..a50f09e1db 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesState.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesState.kt @@ -9,11 +9,12 @@ package io.element.android.features.home.impl.spaces import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.spaces.SpaceRoom +import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableSet data class HomeSpacesState( val space: CurrentSpace, - val spaceRooms: List, + val spaceRooms: ImmutableList, val seenSpaceInvites: ImmutableSet, val hideInvitesAvatar: Boolean, val eventSink: (HomeSpacesEvents) -> Unit, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesStateProvider.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesStateProvider.kt index 921c340886..301c46cb30 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesStateProvider.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesStateProvider.kt @@ -11,6 +11,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.spaces.SpaceRoom import io.element.android.libraries.previewutils.room.aSpaceRoom +import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableSet open class HomeSpacesStateProvider : PreviewParameterProvider { @@ -39,7 +40,7 @@ internal fun aHomeSpacesState( eventSink: (HomeSpacesEvents) -> Unit = {}, ) = HomeSpacesState( space = space, - spaceRooms = spaceRooms, + spaceRooms = spaceRooms.toImmutableList(), seenSpaceInvites = seenSpaceInvites.toImmutableSet(), hideInvitesAvatar = hideInvitesAvatar, eventSink = eventSink, From 0f1ae41b411d63911a493ee15297ddf8cf426900 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 16:57:04 +0200 Subject: [PATCH 05/38] Fix instability of Uri --- .../features/createroom/impl/configureroom/CreateRoomConfig.kt | 3 +++ .../preferences/impl/user/editprofile/EditUserProfileState.kt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfig.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfig.kt index 9ec71f5b76..f157dda2d5 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfig.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfig.kt @@ -8,10 +8,13 @@ package io.element.android.features.createroom.impl.configureroom import android.net.Uri +import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf +// Annotate with @Immutable since `Uri` is unstable +@Immutable data class CreateRoomConfig( val roomName: String? = null, val topic: String? = null, diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileState.kt index 5d3bd1baee..a2d5d7a653 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileState.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileState.kt @@ -8,12 +8,15 @@ package io.element.android.features.preferences.impl.user.editprofile import android.net.Uri +import androidx.compose.runtime.Immutable import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.ui.media.AvatarAction import io.element.android.libraries.permissions.api.PermissionsState import kotlinx.collections.immutable.ImmutableList +// Annotate with @Immutable since `Uri` is unstable +@Immutable data class EditUserProfileState( val userId: UserId, val displayName: String, From f6eed2105583d15682eebaba1b1355ccd6ddbb4f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:00:54 +0200 Subject: [PATCH 06/38] Make AboutState stable --- .../android/features/preferences/impl/about/AboutState.kt | 4 +++- .../features/preferences/impl/about/AboutStateProvider.kt | 3 ++- .../android/features/preferences/impl/about/ElementLegal.kt | 6 ++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/about/AboutState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/about/AboutState.kt index 2c46bf2419..563699b965 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/about/AboutState.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/about/AboutState.kt @@ -7,6 +7,8 @@ package io.element.android.features.preferences.impl.about +import kotlinx.collections.immutable.ImmutableList + data class AboutState( - val elementLegals: List, + val elementLegals: ImmutableList, ) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/about/AboutStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/about/AboutStateProvider.kt index 6d6a4813df..34cbd0b54e 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/about/AboutStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/about/AboutStateProvider.kt @@ -8,6 +8,7 @@ package io.element.android.features.preferences.impl.about import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import kotlinx.collections.immutable.toImmutableList open class AboutStateProvider : PreviewParameterProvider { override val values: Sequence @@ -19,5 +20,5 @@ open class AboutStateProvider : PreviewParameterProvider { fun anAboutState( elementLegals: List = getAllLegals(), ) = AboutState( - elementLegals = elementLegals, + elementLegals = elementLegals.toImmutableList(), ) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/about/ElementLegal.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/about/ElementLegal.kt index a5de31f05d..d9aa7aea65 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/about/ElementLegal.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/about/ElementLegal.kt @@ -10,6 +10,8 @@ package io.element.android.features.preferences.impl.about import androidx.annotation.StringRes import io.element.android.features.preferences.impl.BuildConfig import io.element.android.libraries.ui.strings.CommonStrings +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf private const val COPYRIGHT_URL = BuildConfig.URL_COPYRIGHT private const val USE_POLICY_URL = BuildConfig.URL_ACCEPTABLE_USE @@ -24,8 +26,8 @@ sealed class ElementLegal( data object PrivacyPolicy : ElementLegal(CommonStrings.common_privacy_policy, PRIVACY_URL) } -fun getAllLegals(): List { - return listOf( +fun getAllLegals(): ImmutableList { + return persistentListOf( ElementLegal.Copyright, ElementLegal.AcceptableUsePolicy, ElementLegal.PrivacyPolicy, From 1e6f87347795f3844885d3189ffe78496373698b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:12:47 +0200 Subject: [PATCH 07/38] Make EmojiPickerState stable --- .../components/customreaction/picker/EmojiPickerState.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/picker/EmojiPickerState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/picker/EmojiPickerState.kt index 595349a503..04801a7ee6 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/picker/EmojiPickerState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/picker/EmojiPickerState.kt @@ -8,11 +8,14 @@ package io.element.android.features.messages.impl.timeline.components.customreaction.picker import androidx.annotation.StringRes +import androidx.compose.runtime.Immutable import io.element.android.emojibasebindings.Emoji import io.element.android.libraries.designsystem.theme.components.IconSource import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import kotlinx.collections.immutable.ImmutableList +// Emoji is unstable (because from an external library?), so we annotate with @Immutable +@Immutable data class EmojiPickerState( val categories: ImmutableList, val allEmojis: ImmutableList, From 1e847eaa9f72e63a87dfe302e4c7e3b227019cdf Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:14:23 +0200 Subject: [PATCH 08/38] Make LeaveRoomState stable --- .../element/android/features/leaveroom/api/LeaveRoomState.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/leaveroom/api/src/main/kotlin/io/element/android/features/leaveroom/api/LeaveRoomState.kt b/features/leaveroom/api/src/main/kotlin/io/element/android/features/leaveroom/api/LeaveRoomState.kt index 28cee237a1..7b798018e3 100644 --- a/features/leaveroom/api/src/main/kotlin/io/element/android/features/leaveroom/api/LeaveRoomState.kt +++ b/features/leaveroom/api/src/main/kotlin/io/element/android/features/leaveroom/api/LeaveRoomState.kt @@ -7,6 +7,9 @@ package io.element.android.features.leaveroom.api +import androidx.compose.runtime.Immutable + +@Immutable interface LeaveRoomState { val eventSink: (LeaveRoomEvent) -> Unit } From babe4d7ed050fe9ff1fcec51bfb723895dde9c9f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:15:32 +0200 Subject: [PATCH 09/38] Fix instability of Uri --- .../features/roomdetails/impl/edit/RoomDetailsEditState.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditState.kt index f01011376c..d9a51e8e06 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditState.kt @@ -8,12 +8,15 @@ package io.element.android.features.roomdetails.impl.edit import android.net.Uri +import androidx.compose.runtime.Immutable import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.ui.media.AvatarAction import io.element.android.libraries.permissions.api.PermissionsState import kotlinx.collections.immutable.ImmutableList +// Annotate with @Immutable since `Uri` is unstable +@Immutable data class RoomDetailsEditState( val roomId: RoomId, /** The raw room name (i.e. the room name from the state event `m.room.name`), not the display name. */ From 49fd981157b9722862ee36b59492c10051227524 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:16:25 +0200 Subject: [PATCH 10/38] Make RoomMemberModerationState stable --- .../roommembermoderation/api/RoomMemberModerationState.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationState.kt b/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationState.kt index 368aa283ad..a5589f933a 100644 --- a/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationState.kt +++ b/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationState.kt @@ -7,6 +7,9 @@ package io.element.android.features.roommembermoderation.api +import androidx.compose.runtime.Immutable + +@Immutable interface RoomMemberModerationState { val canKick: Boolean val canBan: Boolean From 89879497043fdd0bf63646795ed19c8962db2dfc Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:20:16 +0200 Subject: [PATCH 11/38] Make ChangeAccountProviderState stable --- .../changeaccountprovider/ChangeAccountProviderPresenter.kt | 2 ++ .../changeaccountprovider/ChangeAccountProviderState.kt | 3 ++- .../ChangeAccountProviderStateProvider.kt | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderPresenter.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderPresenter.kt index 3c725106c8..8e6a3ef0ba 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderPresenter.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderPresenter.kt @@ -17,6 +17,7 @@ import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.changeserver.ChangeServerState import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.uri.ensureProtocol +import kotlinx.collections.immutable.toImmutableList @Inject class ChangeAccountProviderPresenter( @@ -39,6 +40,7 @@ class ChangeAccountProviderPresenter( isValid = true, ) } + .toImmutableList() } val canSearchForAccountProviders = remember { diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderState.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderState.kt index e8e1f21cd8..f6f62eca01 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderState.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderState.kt @@ -9,10 +9,11 @@ package io.element.android.features.login.impl.screens.changeaccountprovider import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.changeserver.ChangeServerState +import kotlinx.collections.immutable.ImmutableList // Do not use default value, so no member get forgotten in the presenters. data class ChangeAccountProviderState( - val accountProviders: List, + val accountProviders: ImmutableList, val canSearchForAccountProviders: Boolean, val changeServerState: ChangeServerState, ) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderStateProvider.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderStateProvider.kt index 435eee7f89..cfc7be0973 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderStateProvider.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderStateProvider.kt @@ -12,6 +12,7 @@ import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.accountprovider.anAccountProvider import io.element.android.features.login.impl.changeserver.ChangeServerState import io.element.android.features.login.impl.changeserver.aChangeServerState +import kotlinx.collections.immutable.toImmutableList open class ChangeAccountProviderStateProvider : PreviewParameterProvider { override val values: Sequence @@ -29,7 +30,7 @@ fun aChangeAccountProviderState( canSearchForAccountProviders: Boolean = true, changeServerState: ChangeServerState = aChangeServerState(), ) = ChangeAccountProviderState( - accountProviders = accountProviders, + accountProviders = accountProviders.toImmutableList(), canSearchForAccountProviders = canSearchForAccountProviders, changeServerState = changeServerState, ) From 417918feed59d44741fd15574f8d4bdde6d27109 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:21:42 +0200 Subject: [PATCH 12/38] Make NotificationTroubleshootTestState.Status stable --- .../troubleshoot/api/test/NotificationTroubleshootTestState.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTestState.kt b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTestState.kt index 4069d78cb3..4a09a3cfd6 100644 --- a/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTestState.kt +++ b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTestState.kt @@ -7,11 +7,14 @@ package io.element.android.libraries.troubleshoot.api.test +import androidx.compose.runtime.Immutable + data class NotificationTroubleshootTestState( val name: String, val description: String, val status: Status, ) { + @Immutable sealed interface Status { data class Idle(val visible: Boolean) : Status data object InProgress : Status From c5848426111ed08a2722f812fe67c60ab6aeac33 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:25:25 +0200 Subject: [PATCH 13/38] Make LeaveSpaceState stable --- .../features/space/impl/leave/LeaveSpaceState.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpaceState.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpaceState.kt index 0f2a0f93f6..0f0cf143b1 100644 --- a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpaceState.kt +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/leave/LeaveSpaceState.kt @@ -10,6 +10,7 @@ package io.element.android.features.space.impl.leave import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList data class LeaveSpaceState( val spaceName: String?, @@ -18,10 +19,15 @@ data class LeaveSpaceState( val leaveSpaceAction: AsyncAction, val eventSink: (LeaveSpaceEvents) -> Unit, ) { - private val rooms = selectableSpaceRooms.dataOrNull().orEmpty() - private val partition = rooms.partition { it.isLastAdmin } - private val lastAdminRooms = partition.first - private val selectableRooms = partition.second + private val rooms = selectableSpaceRooms.dataOrNull().orEmpty().toImmutableList() + private val lastAdminRooms: ImmutableList + private val selectableRooms: ImmutableList + + init { + val partition = rooms.partition { it.isLastAdmin } + lastAdminRooms = partition.first.toImmutableList() + selectableRooms = partition.second.toImmutableList() + } /** * True if we should show the quick action to select/deselect all rooms. From 8f703c2aa7d21e26aa066f818c8af3b9f455f9ac Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:31:11 +0200 Subject: [PATCH 14/38] Rename RoomDirectoryList.State to RoomDirectoryList.SearchResult to avoid this class to be checked for stability. --- .../roomdirectory/impl/root/RoomDirectoryPresenterTest.kt | 8 ++++---- .../matrix/api/roomdirectory/RoomDirectoryList.kt | 4 ++-- .../matrix/impl/roomdirectory/RustRoomDirectoryList.kt | 4 ++-- .../impl/roomdirectory/RustBaseRoomDirectoryListTest.kt | 6 +++--- .../matrix/test/roomdirectory/FakeRoomDirectoryList.kt | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenterTest.kt b/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenterTest.kt index 4af983b307..1e450297ae 100644 --- a/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenterTest.kt +++ b/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenterTest.kt @@ -42,14 +42,14 @@ class RoomDirectoryPresenterTest { @Test fun `present - room directory list emits empty state`() = runTest { - val directoryListStateFlow = MutableSharedFlow(replay = 1) + val directoryListStateFlow = MutableSharedFlow(replay = 1) val roomDirectoryList = FakeRoomDirectoryList(directoryListStateFlow) val roomDirectoryService = FakeRoomDirectoryService { roomDirectoryList } val presenter = createRoomDirectoryPresenter(roomDirectoryService = roomDirectoryService) presenter.test { skipItems(1) directoryListStateFlow.emit( - RoomDirectoryList.State(false, emptyList()) + RoomDirectoryList.SearchResult(false, emptyList()) ) awaitItem().also { state -> assertThat(state.displayEmptyState).isTrue() @@ -60,14 +60,14 @@ class RoomDirectoryPresenterTest { @Test fun `present - room directory list emits non-empty state`() = runTest { - val directoryListStateFlow = MutableSharedFlow(replay = 1) + val directoryListStateFlow = MutableSharedFlow(replay = 1) val roomDirectoryList = FakeRoomDirectoryList(directoryListStateFlow) val roomDirectoryService = FakeRoomDirectoryService { roomDirectoryList } val presenter = createRoomDirectoryPresenter(roomDirectoryService = roomDirectoryService) presenter.test { skipItems(1) directoryListStateFlow.emit( - RoomDirectoryList.State( + RoomDirectoryList.SearchResult( hasMoreToLoad = true, items = listOf(aRoomDescription()) ) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomdirectory/RoomDirectoryList.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomdirectory/RoomDirectoryList.kt index 402a60f639..b9d82128fb 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomdirectory/RoomDirectoryList.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomdirectory/RoomDirectoryList.kt @@ -26,9 +26,9 @@ interface RoomDirectoryList { /** * The current search results as a state flow. */ - val state: Flow + val state: Flow - data class State( + data class SearchResult( val hasMoreToLoad: Boolean, val items: List, ) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryList.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryList.kt index e91fef7810..4de2943673 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryList.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryList.kt @@ -73,9 +73,9 @@ class RustRoomDirectoryList( return !inner.isAtLastPage() } - override val state: Flow = + override val state: Flow = combine(hasMoreToLoad, processor.roomDescriptionsFlow) { hasMoreToLoad, items -> - RoomDirectoryList.State( + RoomDirectoryList.SearchResult( hasMoreToLoad = hasMoreToLoad, items = items ) diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustBaseRoomDirectoryListTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustBaseRoomDirectoryListTest.kt index 460ef37e99..89b16e6ff5 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustBaseRoomDirectoryListTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustBaseRoomDirectoryListTest.kt @@ -42,7 +42,7 @@ class RustBaseRoomDirectoryListTest { ) val initialItem = awaitItem() assertThat(initialItem).isEqualTo( - RoomDirectoryList.State( + RoomDirectoryList.SearchResult( hasMoreToLoad = true, items = listOf(mapper.map(aRustRoomDescription())) ) @@ -57,7 +57,7 @@ class RustBaseRoomDirectoryListTest { ) val nextItem = awaitItem() assertThat(nextItem).isEqualTo( - RoomDirectoryList.State( + RoomDirectoryList.SearchResult( hasMoreToLoad = false, items = listOf( mapper.map(aRustRoomDescription()), @@ -66,7 +66,7 @@ class RustBaseRoomDirectoryListTest { ) val finalItem = awaitItem() assertThat(finalItem).isEqualTo( - RoomDirectoryList.State( + RoomDirectoryList.SearchResult( hasMoreToLoad = false, items = listOf( mapper.map(aRustRoomDescription()), diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomdirectory/FakeRoomDirectoryList.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomdirectory/FakeRoomDirectoryList.kt index 33c8bc83b5..54ad389e4c 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomdirectory/FakeRoomDirectoryList.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomdirectory/FakeRoomDirectoryList.kt @@ -12,7 +12,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow class FakeRoomDirectoryList( - override val state: Flow = emptyFlow(), + override val state: Flow = emptyFlow(), val filterLambda: (String?, Int, String?) -> Result = { _, _, _ -> Result.success(Unit) }, val loadMoreLambda: () -> Result = { Result.success(Unit) } ) : RoomDirectoryList { From 2c7f9230f0fecb838cdc9fc9d82e28f7d35e8c04 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:36:06 +0200 Subject: [PATCH 15/38] Need to be a compose library for PushHistoryItem to be considered stable. --- libraries/push/api/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/push/api/build.gradle.kts b/libraries/push/api/build.gradle.kts index 48df34053a..0db811e299 100644 --- a/libraries/push/api/build.gradle.kts +++ b/libraries/push/api/build.gradle.kts @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ plugins { - id("io.element.android-library") + id("io.element.android-compose-library") } android { From 27557fc2b24ed3e42d126aee3e0f3796de870e3c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:37:09 +0200 Subject: [PATCH 16/38] Need to be a compose library for UserProfileState to be considered stable. --- features/userprofile/api/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/userprofile/api/build.gradle.kts b/features/userprofile/api/build.gradle.kts index 8bdaa8d77e..dd18ebd09e 100644 --- a/features/userprofile/api/build.gradle.kts +++ b/features/userprofile/api/build.gradle.kts @@ -6,7 +6,7 @@ */ plugins { - id("io.element.android-library") + id("io.element.android-compose-library") id("kotlin-parcelize") } From 589954203b2720cddfca933a36f651065baa4653 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:39:01 +0200 Subject: [PATCH 17/38] Make Role stable --- .../io/element/android/libraries/matrix/api/room/RoomMember.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt index f1b1104a27..4f57703f60 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt @@ -7,6 +7,7 @@ package io.element.android.libraries.matrix.api.room +import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.user.MatrixUser @@ -24,6 +25,7 @@ data class RoomMember( /** * Role of the RoomMember, based on its [powerLevel]. */ + @Immutable sealed interface Role { data class Owner(val isCreator: Boolean) : Role data object Admin : Role From c33815ccd3f5998f0d229ba1492a01df43d5dcf1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:41:37 +0200 Subject: [PATCH 18/38] Need to be a compose library for NotificationTroubleshootTestState to be considered stable. --- libraries/troubleshoot/api/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/troubleshoot/api/build.gradle.kts b/libraries/troubleshoot/api/build.gradle.kts index 6ce2d3e9f8..9748511d3c 100644 --- a/libraries/troubleshoot/api/build.gradle.kts +++ b/libraries/troubleshoot/api/build.gradle.kts @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ plugins { - id("io.element.android-library") + id("io.element.android-compose-library") } android { From 403a58d7a7c5b71b110f1f282826f81c40ee62e8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:46:02 +0200 Subject: [PATCH 19/38] Make ChooseAccountProviderState stable --- .../chooseaccountprovider/ChooseAccountProviderPresenter.kt | 2 ++ .../chooseaccountprovider/ChooseAccountProviderState.kt | 3 ++- .../ChooseAccountProviderStateProvider.kt | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderPresenter.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderPresenter.kt index d259454f18..73f03ba7c8 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderPresenter.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderPresenter.kt @@ -21,6 +21,7 @@ import io.element.android.features.login.impl.login.LoginHelper import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.uri.ensureProtocol +import kotlinx.collections.immutable.toImmutableList @Inject class ChooseAccountProviderPresenter( @@ -69,6 +70,7 @@ class ChooseAccountProviderPresenter( isValid = true, ) } + .toImmutableList() } return ChooseAccountProviderState( diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderState.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderState.kt index 3591334047..ad4677ea24 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderState.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderState.kt @@ -10,10 +10,11 @@ package io.element.android.features.login.impl.screens.chooseaccountprovider import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.login.LoginMode import io.element.android.libraries.architecture.AsyncData +import kotlinx.collections.immutable.ImmutableList // Do not use default value, so no member get forgotten in the presenters. data class ChooseAccountProviderState( - val accountProviders: List, + val accountProviders: ImmutableList, val selectedAccountProvider: AccountProvider?, val loginMode: AsyncData, val eventSink: (ChooseAccountProviderEvents) -> Unit, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderStateProvider.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderStateProvider.kt index b921fee330..8dc059285e 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderStateProvider.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderStateProvider.kt @@ -12,6 +12,7 @@ import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.accountprovider.anAccountProvider import io.element.android.features.login.impl.login.LoginMode import io.element.android.libraries.architecture.AsyncData +import kotlinx.collections.immutable.toImmutableList open class ChooseAccountProviderStateProvider : PreviewParameterProvider { private val server1 = anAccountProvider( @@ -70,7 +71,7 @@ fun aChooseAccountProviderState( loginMode: AsyncData = AsyncData.Uninitialized, eventSink: (ChooseAccountProviderEvents) -> Unit = {}, ) = ChooseAccountProviderState( - accountProviders = accountProviders, + accountProviders = accountProviders.toImmutableList(), selectedAccountProvider = selectedAccountProvider, loginMode = loginMode, eventSink = eventSink, From 5e7437e82759e7bdc1a042b18511955057c222b8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 17:49:49 +0200 Subject: [PATCH 20/38] Rename SavedState to SavedValue to avoid this class to be checked for stability. --- .../textcomposer/model/MarkdownTextEditorState.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/MarkdownTextEditorState.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/MarkdownTextEditorState.kt index 14f56f3bbb..918550f5a6 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/MarkdownTextEditorState.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/MarkdownTextEditorState.kt @@ -128,15 +128,15 @@ class MarkdownTextEditorState( } @Parcelize - data class SavedState( + data class SavedValue( val text: CharSequence, val selectionStart: Int, val selectionEnd: Int, ) : Parcelable } -object MarkdownTextEditorStateSaver : Saver { - override fun restore(value: MarkdownTextEditorState.SavedState): MarkdownTextEditorState { +object MarkdownTextEditorStateSaver : Saver { + override fun restore(value: MarkdownTextEditorState.SavedValue): MarkdownTextEditorState { return MarkdownTextEditorState( initialText = "", initialFocus = false, @@ -146,8 +146,8 @@ object MarkdownTextEditorStateSaver : Saver Date: Thu, 9 Oct 2025 18:03:32 +0200 Subject: [PATCH 21/38] Remove useless Immutable annotation --- .../main/kotlin/io/element/android/appnav/root/RootState.kt | 2 -- .../kotlin/io/element/android/features/home/impl/HomeState.kt | 2 -- .../android/features/home/impl/roomlist/RoomListState.kt | 1 - .../io/element/android/features/joinroom/impl/JoinRoomState.kt | 1 - .../features/knockrequests/impl/list/KnockRequestsListState.kt | 2 -- .../io/element/android/features/messages/impl/MessagesState.kt | 2 -- .../features/messages/impl/actionlist/ActionListState.kt | 1 - .../messages/impl/actionlist/model/TimelineItemAction.kt | 2 -- .../android/features/messages/impl/timeline/TimelineState.kt | 2 -- .../receipt/bottomsheet/ReadReceiptBottomSheetState.kt | 2 -- .../messages/impl/timeline/model/AggregatedReactionSender.kt | 2 -- .../features/messages/impl/timeline/model/TimelineItem.kt | 3 --- .../impl/notifications/NotificationSettingsState.kt | 2 -- .../features/rageshake/api/crash/CrashDetectionState.kt | 3 --- .../rageshake/api/detection/RageshakeDetectionState.kt | 2 -- .../features/roomaliasresolver/impl/RoomAliasResolverState.kt | 2 -- .../android/features/roomdirectory/api/RoomDescription.kt | 2 -- .../verifysession/impl/incoming/IncomingVerificationState.kt | 2 -- .../verifysession/impl/outgoing/OutgoingVerificationState.kt | 2 -- .../android/compound/tokens/generated/SemanticColors.kt | 1 - .../libraries/designsystem/components/avatar/AvatarData.kt | 2 -- .../io/element/android/libraries/matrix/api/room/RoomInfo.kt | 2 -- .../libraries/matrix/api/timeline/item/event/EventReaction.kt | 2 -- .../android/libraries/matrix/impl/room/NotJoinedRustRoom.kt | 2 -- .../android/libraries/matrix/test/room/FakeNotJoinedRoom.kt | 2 -- .../element/android/libraries/matrix/ui/model/InviteSender.kt | 2 -- 26 files changed, 50 deletions(-) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/root/RootState.kt b/appnav/src/main/kotlin/io/element/android/appnav/root/RootState.kt index 3ea7362efa..154f7f0dc9 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/root/RootState.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/root/RootState.kt @@ -7,12 +7,10 @@ package io.element.android.appnav.root -import androidx.compose.runtime.Immutable import io.element.android.features.rageshake.api.crash.CrashDetectionState import io.element.android.features.rageshake.api.detection.RageshakeDetectionState import io.element.android.services.apperror.api.AppErrorState -@Immutable data class RootState( val rageshakeDetectionState: RageshakeDetectionState, val crashDetectionState: CrashDetectionState, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt index d35412734f..fdaf01e9aa 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt @@ -7,7 +7,6 @@ package io.element.android.features.home.impl -import androidx.compose.runtime.Immutable import io.element.android.features.home.impl.roomlist.RoomListState import io.element.android.features.home.impl.spaces.HomeSpacesState import io.element.android.features.logout.api.direct.DirectLogoutState @@ -15,7 +14,6 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.collections.immutable.ImmutableList -@Immutable data class HomeState( /** * The current user of this session, in case of multiple accounts, will contains 3 items, with the diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListState.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListState.kt index 80cd6394e8..8f574443c4 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListState.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListState.kt @@ -19,7 +19,6 @@ import io.element.android.libraries.push.api.battery.BatteryOptimizationState import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableSet -@Immutable data class RoomListState( val contextMenu: ContextMenu, val declineInviteMenu: DeclineInviteMenu, diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomState.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomState.kt index f27a290f5d..f6dc5c36af 100644 --- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomState.kt +++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomState.kt @@ -24,7 +24,6 @@ import kotlinx.collections.immutable.ImmutableList internal const val MAX_KNOCK_MESSAGE_LENGTH = 500 -@Immutable data class JoinRoomState( val roomIdOrAlias: RoomIdOrAlias, val contentState: ContentState, diff --git a/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListState.kt b/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListState.kt index 1042a3646f..5788dbed2a 100644 --- a/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListState.kt +++ b/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListState.kt @@ -7,7 +7,6 @@ package io.element.android.features.knockrequests.impl.list -import androidx.compose.runtime.Immutable import io.element.android.features.knockrequests.impl.data.KnockRequestPermissions import io.element.android.features.knockrequests.impl.data.KnockRequestPresentable import io.element.android.libraries.architecture.AsyncAction @@ -24,7 +23,6 @@ data class KnockRequestsListState( val canAcceptAll = permissions.canAccept && knockRequests is AsyncData.Success && knockRequests.data.size > 1 } -@Immutable sealed interface KnockRequestsAction { data object None : KnockRequestsAction data class Accept(val knockRequest: KnockRequestPresentable) : KnockRequestsAction diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt index 3d05da5a3c..b92a0fc9d1 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt @@ -7,7 +7,6 @@ package io.element.android.features.messages.impl -import androidx.compose.runtime.Immutable import io.element.android.features.messages.api.timeline.voicemessages.composer.VoiceMessageComposerState import io.element.android.features.messages.impl.actionlist.ActionListState import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState @@ -29,7 +28,6 @@ import io.element.android.libraries.matrix.api.encryption.identity.IdentityState import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom import kotlinx.collections.immutable.ImmutableList -@Immutable data class MessagesState( val roomId: RoomId, val roomName: String?, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListState.kt index 7524a737ff..490ece9c4b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListState.kt @@ -13,7 +13,6 @@ import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUser import io.element.android.features.messages.impl.timeline.model.TimelineItem import kotlinx.collections.immutable.ImmutableList -@Immutable data class ActionListState( val target: Target, val eventSink: (ActionListEvents) -> Unit, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt index ab02e6caea..04696ae787 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt @@ -9,11 +9,9 @@ package io.element.android.features.messages.impl.actionlist.model import androidx.annotation.DrawableRes import androidx.annotation.StringRes -import androidx.compose.runtime.Immutable import io.element.android.libraries.designsystem.icons.CompoundDrawables import io.element.android.libraries.ui.strings.CommonStrings -@Immutable enum class TimelineItemAction( @StringRes val titleRes: Int, @DrawableRes val icon: Int, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt index bd1c58c9d7..d0fed3aef4 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt @@ -21,7 +21,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield import kotlinx.collections.immutable.ImmutableList import kotlin.time.Duration -@Immutable data class TimelineState( val timelineItems: ImmutableList, val timelineRoomInfo: TimelineRoomInfo, @@ -72,7 +71,6 @@ sealed interface FocusRequestState { } } -@Immutable data class TimelineRoomInfo( val isDm: Boolean, val name: String?, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/bottomsheet/ReadReceiptBottomSheetState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/bottomsheet/ReadReceiptBottomSheetState.kt index c143887584..1de3d23f50 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/bottomsheet/ReadReceiptBottomSheetState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/bottomsheet/ReadReceiptBottomSheetState.kt @@ -7,10 +7,8 @@ package io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet -import androidx.compose.runtime.Immutable import io.element.android.features.messages.impl.timeline.model.TimelineItem -@Immutable data class ReadReceiptBottomSheetState( val selectedEvent: TimelineItem.Event?, val eventSink: (ReadReceiptBottomSheetEvents) -> Unit, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionSender.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionSender.kt index 9da9781bc8..6dc77b545f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionSender.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionSender.kt @@ -7,12 +7,10 @@ package io.element.android.features.messages.impl.timeline.model -import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.user.MatrixUser import java.util.Date -@Immutable data class AggregatedReactionSender( val senderId: UserId, val timestamp: Date, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt index 5591616517..6749d9cf99 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt @@ -57,13 +57,11 @@ sealed interface TimelineItem { is GroupedEvents -> "groupedEvent" } - @Immutable data class Virtual( val id: UniqueId, val model: TimelineItemVirtualModel ) : TimelineItem - @Immutable data class Event( val id: UniqueId, // Note: eventId can be null when the event is a local echo @@ -124,7 +122,6 @@ sealed interface TimelineItem { val sendhandle: SendHandle? get() = sendHandleProvider() } - @Immutable data class GroupedEvents( val id: UniqueId, val events: ImmutableList, diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsState.kt index a7a1bf9192..6e60b24115 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsState.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsState.kt @@ -7,7 +7,6 @@ package io.element.android.features.preferences.impl.notifications -import androidx.compose.runtime.Immutable import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermissionsState @@ -15,7 +14,6 @@ import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.pushproviders.api.Distributor import kotlinx.collections.immutable.ImmutableList -@Immutable data class NotificationSettingsState( val matrixSettings: MatrixSettings, val appSettings: AppSettings, diff --git a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionState.kt b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionState.kt index 66c206adcd..4ad69316ab 100644 --- a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionState.kt +++ b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/crash/CrashDetectionState.kt @@ -7,9 +7,6 @@ package io.element.android.features.rageshake.api.crash -import androidx.compose.runtime.Immutable - -@Immutable data class CrashDetectionState( val appName: String, val crashDetected: Boolean, diff --git a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionState.kt b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionState.kt index 8ace909da3..af52a70dde 100644 --- a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionState.kt +++ b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/detection/RageshakeDetectionState.kt @@ -7,10 +7,8 @@ package io.element.android.features.rageshake.api.detection -import androidx.compose.runtime.Immutable import io.element.android.features.rageshake.api.preferences.RageshakePreferencesState -@Immutable data class RageshakeDetectionState( val takeScreenshot: Boolean, val showDialog: Boolean, diff --git a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverState.kt b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverState.kt index dc858621f7..e52c093e52 100644 --- a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverState.kt +++ b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverState.kt @@ -7,12 +7,10 @@ package io.element.android.features.roomaliasresolver.impl -import androidx.compose.runtime.Immutable import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias -@Immutable data class RoomAliasResolverState( val roomAlias: RoomAlias, val resolveState: AsyncData, diff --git a/features/roomdirectory/api/src/main/kotlin/io/element/android/features/roomdirectory/api/RoomDescription.kt b/features/roomdirectory/api/src/main/kotlin/io/element/android/features/roomdirectory/api/RoomDescription.kt index 7d479cbad9..a48a38ccb2 100644 --- a/features/roomdirectory/api/src/main/kotlin/io/element/android/features/roomdirectory/api/RoomDescription.kt +++ b/features/roomdirectory/api/src/main/kotlin/io/element/android/features/roomdirectory/api/RoomDescription.kt @@ -8,7 +8,6 @@ package io.element.android.features.roomdirectory.api import android.os.Parcelable -import androidx.compose.runtime.Immutable import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.matrix.api.core.RoomAlias @@ -17,7 +16,6 @@ import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize @Parcelize -@Immutable data class RoomDescription( val roomId: RoomId, val name: String?, diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationState.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationState.kt index 00bffa4ce3..3c6822d19d 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationState.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationState.kt @@ -7,13 +7,11 @@ package io.element.android.features.verifysession.impl.incoming -import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable import io.element.android.libraries.matrix.api.core.DeviceId import io.element.android.libraries.matrix.api.verification.SessionVerificationData import io.element.android.libraries.matrix.api.verification.VerificationRequest -@Immutable data class IncomingVerificationState( val step: Step, val request: VerificationRequest.Incoming, diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationState.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationState.kt index 9b2d5f2e40..9946c2f2bd 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationState.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationState.kt @@ -7,13 +7,11 @@ package io.element.android.features.verifysession.impl.outgoing -import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.matrix.api.verification.SessionVerificationData import io.element.android.libraries.matrix.api.verification.VerificationRequest -@Immutable data class OutgoingVerificationState( val step: Step, val request: VerificationRequest.Outgoing, diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColors.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColors.kt index 8da51213f8..01adfd4eaa 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColors.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColors.kt @@ -26,7 +26,6 @@ import androidx.compose.ui.graphics.Color /** * This class holds all the semantic tokens of the Compound theme. */ -@Immutable data class SemanticColors( /** Background colour for accent or brand actions. State: Hover */ val bgAccentHovered: Color, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/AvatarData.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/AvatarData.kt index 2e711ee6eb..b6dcdec206 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/AvatarData.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/AvatarData.kt @@ -7,11 +7,9 @@ package io.element.android.libraries.designsystem.components.avatar -import androidx.compose.runtime.Immutable import io.element.android.libraries.core.data.tryOrNull import java.text.BreakIterator -@Immutable data class AvatarData( val id: String, val name: String?, diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomInfo.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomInfo.kt index 48e549ab3f..21165ae6d7 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomInfo.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomInfo.kt @@ -7,7 +7,6 @@ package io.element.android.libraries.matrix.api.room -import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId @@ -19,7 +18,6 @@ import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.collections.immutable.ImmutableList -@Immutable data class RoomInfo( val id: RoomId, /** The room's name from the room state event if received from sync, or one that's been computed otherwise. */ diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventReaction.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventReaction.kt index ee304957b2..bc92aeaa9f 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventReaction.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventReaction.kt @@ -7,10 +7,8 @@ package io.element.android.libraries.matrix.api.timeline.item.event -import androidx.compose.runtime.Immutable import kotlinx.collections.immutable.ImmutableList -@Immutable data class EventReaction( val key: String, val senders: ImmutableList diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/NotJoinedRustRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/NotJoinedRustRoom.kt index fb88cf625b..a9218ac001 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/NotJoinedRustRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/NotJoinedRustRoom.kt @@ -7,7 +7,6 @@ package io.element.android.libraries.matrix.impl.room -import androidx.compose.runtime.Immutable import io.element.android.libraries.core.extensions.runCatchingExceptions import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.room.NotJoinedRoom @@ -15,7 +14,6 @@ import io.element.android.libraries.matrix.api.room.RoomMembershipDetails import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper -@Immutable class NotJoinedRustRoom( private val sessionId: SessionId, override val localRoom: RustBaseRoom?, diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeNotJoinedRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeNotJoinedRoom.kt index 7691aa58c6..69d29c3a2d 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeNotJoinedRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeNotJoinedRoom.kt @@ -7,7 +7,6 @@ package io.element.android.libraries.matrix.test.room -import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.NotJoinedRoom import io.element.android.libraries.matrix.api.room.RoomMembershipDetails @@ -15,7 +14,6 @@ import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.simulateLongTask -@Immutable class FakeNotJoinedRoom( override val localRoom: BaseRoom? = null, override val previewInfo: RoomPreviewInfo = aRoomPreviewInfo(), diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/InviteSender.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/InviteSender.kt index 778d535fc6..b89fb0143b 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/InviteSender.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/InviteSender.kt @@ -8,7 +8,6 @@ package io.element.android.libraries.matrix.ui.model import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString @@ -21,7 +20,6 @@ import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.ui.R -@Immutable data class InviteSender( val userId: UserId, val displayName: String, From 733a33f4ea01a65dc5fbefa0b386156c01895439 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 18:03:59 +0200 Subject: [PATCH 22/38] Need to be a compose library for FullScreenIntentPermissionsState to be considered stable. --- libraries/fullscreenintent/api/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fullscreenintent/api/build.gradle.kts b/libraries/fullscreenintent/api/build.gradle.kts index 4bd0a50cb7..d1a1323198 100644 --- a/libraries/fullscreenintent/api/build.gradle.kts +++ b/libraries/fullscreenintent/api/build.gradle.kts @@ -6,7 +6,7 @@ */ plugins { - id("io.element.android-library") + id("io.element.android-compose-library") } android { From f0cfe6a777130a27c8d2fcd7f40f1634d8328352 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 18:04:31 +0200 Subject: [PATCH 23/38] Need to be a compose library for RoomDescription to be considered stable. --- features/roomdirectory/api/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/roomdirectory/api/build.gradle.kts b/features/roomdirectory/api/build.gradle.kts index ee27b5b21a..b7d3c9df51 100644 --- a/features/roomdirectory/api/build.gradle.kts +++ b/features/roomdirectory/api/build.gradle.kts @@ -6,7 +6,7 @@ */ plugins { - id("io.element.android-library") + id("io.element.android-compose-library") id("kotlin-parcelize") } From 2d9b0349405343290134b402255d7d55d8e1dd22 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 18:05:43 +0200 Subject: [PATCH 24/38] Make Outgoing stable --- .../libraries/matrix/api/verification/VerificationRequest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/VerificationRequest.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/VerificationRequest.kt index f26afe50f6..7c1a0cbd2e 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/VerificationRequest.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/VerificationRequest.kt @@ -8,10 +8,12 @@ package io.element.android.libraries.matrix.api.verification import android.os.Parcelable +import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.core.UserId import kotlinx.parcelize.Parcelize sealed interface VerificationRequest : Parcelable { + @Immutable sealed interface Outgoing : VerificationRequest { @Parcelize data object CurrentSession : Outgoing From 47e664e5d17b7b0e21cf1451819006e8b8286bbe Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 18:07:35 +0200 Subject: [PATCH 25/38] Make TimelineRoomInfo stable --- .../messages/impl/pinned/list/PinnedMessagesListPresenter.kt | 2 +- .../android/features/messages/impl/timeline/TimelineState.kt | 2 +- .../features/messages/impl/timeline/TimelineStateProvider.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt index 0c7fb8948a..50652bb6e5 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt @@ -105,7 +105,7 @@ class PinnedMessagesListPresenter( // We do not care about the call state here. roomCallState = aStandByCallState(), // don't compute this value or the pin icon will be shown - pinnedEventIds = emptyList(), + pinnedEventIds = persistentListOf(), typingNotificationState = TypingNotificationState( renderTypingNotifications = false, typingMembers = persistentListOf(), diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt index d0fed3aef4..76899de1c3 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt @@ -77,7 +77,7 @@ data class TimelineRoomInfo( val userHasPermissionToSendMessage: Boolean, val userHasPermissionToSendReaction: Boolean, val roomCallState: RoomCallState, - val pinnedEventIds: List, + val pinnedEventIds: ImmutableList, val typingNotificationState: TypingNotificationState, val predecessorRoom: PredecessorRoom?, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt index 0cc61b4e4c..bcd32cf9f6 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt @@ -259,7 +259,7 @@ internal fun aTimelineRoomInfo( userHasPermissionToSendMessage = userHasPermissionToSendMessage, userHasPermissionToSendReaction = true, roomCallState = aStandByCallState(), - pinnedEventIds = pinnedEventIds, + pinnedEventIds = pinnedEventIds.toImmutableList(), typingNotificationState = typingNotificationState, predecessorRoom = predecessorRoom, ) From 146c5d4adc74db60950c1c61cfae97530068f11d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 18:10:03 +0200 Subject: [PATCH 26/38] Need to be a compose library for Distributor to be considered stable. --- libraries/pushproviders/api/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/pushproviders/api/build.gradle.kts b/libraries/pushproviders/api/build.gradle.kts index 587b38f617..1758588f8a 100644 --- a/libraries/pushproviders/api/build.gradle.kts +++ b/libraries/pushproviders/api/build.gradle.kts @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ plugins { - id("io.element.android-library") + id("io.element.android-compose-library") } android { From 264cf9e1b35b53ef7d7582f82637100f9319cbbf Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 18:14:20 +0200 Subject: [PATCH 27/38] Make VerificationRequest stable --- .../libraries/matrix/api/verification/VerificationRequest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/VerificationRequest.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/VerificationRequest.kt index 7c1a0cbd2e..1690df7a6b 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/VerificationRequest.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/VerificationRequest.kt @@ -12,6 +12,7 @@ import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.core.UserId import kotlinx.parcelize.Parcelize +@Immutable sealed interface VerificationRequest : Parcelable { @Immutable sealed interface Outgoing : VerificationRequest { From d932e068d421a86ae7368736c63a25b0b8192a13 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 18:16:17 +0200 Subject: [PATCH 28/38] Make AggregatedReactionSender stable --- .../messages/impl/timeline/model/AggregatedReactionSender.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionSender.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionSender.kt index 6dc77b545f..cce557d0ec 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionSender.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionSender.kt @@ -7,10 +7,13 @@ package io.element.android.features.messages.impl.timeline.model +import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.user.MatrixUser import java.util.Date +// Need to be marked as @Immutable for Date +@Immutable data class AggregatedReactionSender( val senderId: UserId, val timestamp: Date, From 245509cd88fc1d49a26eee07373b263ee291976d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 18:18:05 +0200 Subject: [PATCH 29/38] Make Timeline.Mode stable --- .../element/android/libraries/matrix/api/timeline/Timeline.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt index f8f5793368..ad526fa787 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt @@ -8,6 +8,7 @@ package io.element.android.libraries.matrix.api.timeline import android.os.Parcelable +import androidx.compose.runtime.Immutable 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.ThreadId @@ -42,6 +43,7 @@ interface Timeline : AutoCloseable { } @Parcelize + @Immutable sealed interface Mode : Parcelable { data object Live : Mode data class FocusedOnEvent(val eventId: EventId) : Mode From 45a3018b112a3ef55348f06163ea886a6c7a140a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 18:21:23 +0200 Subject: [PATCH 30/38] Add new tool to the list of CI checks --- .github/workflows/quality.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 773bc02d93..b9b9e25071 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -103,6 +103,39 @@ jobs: path: | **/build/reports/**/*.* + compose: + name: Compose tests + runs-on: ubuntu-latest + # Allow all jobs on main and develop. Just one per PR. + concurrency: + group: ${{ github.ref == 'refs/heads/main' && format('check-compose-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-compose-develop-{0}', github.sha) || format('check-compose-{0}', github.ref) }} + cancel-in-progress: true + steps: + - uses: actions/checkout@v5 + with: + # Ensure we are building the branch and not the branch after being merged on develop + # https://github.com/actions/checkout/issues/881 + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }} + - name: Add SSH private keys for submodule repositories + uses: webfactory/ssh-agent@a6f90b1f127823b31d4d4a8d96047790581349bd # v0.9.1 + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} + with: + ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }} + - name: Clone submodules + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} + run: git submodule update --init --recursive + - name: Use JDK 21 + uses: actions/setup-java@v5 + with: + distribution: 'temurin' # See 'Supported distributions' for available options + java-version: '21' + - name: Configure gradle + uses: gradle/actions/setup-gradle@v5 + with: + cache-read-only: ${{ github.ref != 'refs/heads/develop' }} + - name: Run compose tests + run: ./tools/compose/check_stability.sh + lint: name: Android lint check runs-on: ubuntu-latest From 3b390741443380a49a64e7ac3d2b7a4c56941d06 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Oct 2025 21:06:25 +0200 Subject: [PATCH 31/38] KnockRequestsAction needs to be immutable --- .../features/knockrequests/impl/list/KnockRequestsListState.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListState.kt b/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListState.kt index 5788dbed2a..1042a3646f 100644 --- a/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListState.kt +++ b/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListState.kt @@ -7,6 +7,7 @@ package io.element.android.features.knockrequests.impl.list +import androidx.compose.runtime.Immutable import io.element.android.features.knockrequests.impl.data.KnockRequestPermissions import io.element.android.features.knockrequests.impl.data.KnockRequestPresentable import io.element.android.libraries.architecture.AsyncAction @@ -23,6 +24,7 @@ data class KnockRequestsListState( val canAcceptAll = permissions.canAccept && knockRequests is AsyncData.Success && knockRequests.data.size > 1 } +@Immutable sealed interface KnockRequestsAction { data object None : KnockRequestsAction data class Accept(val knockRequest: KnockRequestPresentable) : KnockRequestsAction From b282e310c3d93991b7859e03aa70a83d5bcbc325 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 10 Oct 2025 09:45:10 +0200 Subject: [PATCH 32/38] Make error message more visible --- tools/compose/check_stability.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/compose/check_stability.sh b/tools/compose/check_stability.sh index c965c787cd..06d76ca0ae 100755 --- a/tools/compose/check_stability.sh +++ b/tools/compose/check_stability.sh @@ -17,7 +17,7 @@ find . -type f -name "*-classes.txt" | while read -r file; do # echo "Processing $file" # Check that there is no line containing "unstable class .*State {" if grep -E 'unstable class .*State \{' "$file"; then - echo "Found unstable State class in $file" + echo "❌ ERROR: Found unstable State class in $file" exit 1 fi done From 2b21e12f97ed629311253ac23a8d3a81a2855cc0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 10 Oct 2025 10:02:47 +0200 Subject: [PATCH 33/38] Only timestamp is usefull, no need to build a Date. --- .../timeline/factories/event/TimelineItemEventFactory.kt | 3 +-- .../impl/timeline/model/AggregatedReactionProvider.kt | 5 +++-- .../impl/timeline/model/AggregatedReactionSender.kt | 6 +----- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt index 6043cb57ff..93a5e686d9 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt @@ -146,10 +146,9 @@ class TimelineItemEventFactory( senders = reaction.senders .sortedByDescending { it.timestamp } .map { - val date = Date(it.timestamp) AggregatedReactionSender( senderId = it.senderId, - timestamp = date, + timestamp = it.timestamp, sentTime = dateFormatter.format( it.timestamp, DateFormatterMode.TimeOrDate, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionProvider.kt index b7400c7616..71d5035910 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionProvider.kt @@ -33,13 +33,14 @@ fun anAggregatedReaction( val timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT, java.util.Locale.US).apply { timeZone = TimeZone.getTimeZone("UTC") } - val date = Date(1_689_061_264L) + val timestamp = 1_689_061_264L + val date = Date(timestamp) val senders = buildList { repeat(count) { index -> add( AggregatedReactionSender( senderId = if (isHighlighted && index == 0) userId else UserId("@user$index:server.org"), - timestamp = date, + timestamp = timestamp, sentTime = timeFormatter.format(date), ) ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionSender.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionSender.kt index cce557d0ec..ab8e9fe1a2 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionSender.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/AggregatedReactionSender.kt @@ -7,16 +7,12 @@ package io.element.android.features.messages.impl.timeline.model -import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.user.MatrixUser -import java.util.Date -// Need to be marked as @Immutable for Date -@Immutable data class AggregatedReactionSender( val senderId: UserId, - val timestamp: Date, + val timestamp: Long, val sentTime: String, val user: MatrixUser? = null ) From 84c2752480eeeee180661532d49639684891365b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 10 Oct 2025 10:10:13 +0200 Subject: [PATCH 34/38] Do not create a new immutable list from a List every time we want to produce a new state --- .../features/home/impl/spaces/HomeSpacesPresenter.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt index 9486e6be62..b4a2fc9339 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesPresenter.kt @@ -16,6 +16,7 @@ import io.element.android.features.invite.api.SeenInvitesStore import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.ui.safety.rememberHideInvitesAvatar +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableSet @@ -29,7 +30,10 @@ class HomeSpacesPresenter( @Composable override fun present(): HomeSpacesState { val hideInvitesAvatar by client.rememberHideInvitesAvatar() - val spaceRooms by client.spaceService.spaceRoomsFlow.collectAsState(emptyList()) + val spaceRooms by remember { + client.spaceService.spaceRoomsFlow.map { it.toImmutableList() } + }.collectAsState(persistentListOf()) + val seenSpaceInvites by remember { seenInvitesStore.seenRoomIds().map { it.toImmutableSet() } }.collectAsState(persistentSetOf()) @@ -40,7 +44,7 @@ class HomeSpacesPresenter( return HomeSpacesState( space = CurrentSpace.Root, - spaceRooms = spaceRooms.toImmutableList(), + spaceRooms = spaceRooms, seenSpaceInvites = seenSpaceInvites, hideInvitesAvatar = hideInvitesAvatar, eventSink = ::handleEvents, From 062bebf0306e1b8048c518fd6c8fc427f50b7941 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 10 Oct 2025 10:26:39 +0200 Subject: [PATCH 35/38] Rename SaveableCameraPositionState to SaveableCameraPositionData to avoid this class to be checked for stability. --- .../libraries/maplibre/compose/CameraPositionState.kt | 6 +++--- plugins/src/main/kotlin/extension/KoverExtension.kt | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/maplibre-compose/src/main/kotlin/io/element/android/libraries/maplibre/compose/CameraPositionState.kt b/libraries/maplibre-compose/src/main/kotlin/io/element/android/libraries/maplibre/compose/CameraPositionState.kt index b5b46ca847..922311ee70 100644 --- a/libraries/maplibre-compose/src/main/kotlin/io/element/android/libraries/maplibre/compose/CameraPositionState.kt +++ b/libraries/maplibre-compose/src/main/kotlin/io/element/android/libraries/maplibre/compose/CameraPositionState.kt @@ -156,8 +156,8 @@ public class CameraPositionState( /** * The default saver implementation for [CameraPositionState]. */ - public val Saver: Saver = Saver( - save = { SaveableCameraPositionState(it.position, it.cameraMode.toInternal()) }, + public val Saver: Saver = Saver( + save = { SaveableCameraPositionData(it.position, it.cameraMode.toInternal()) }, restore = { CameraPositionState(it.position, CameraMode.fromInternal(it.cameraMode)) } ) } @@ -172,7 +172,7 @@ public val currentCameraPositionState: CameraPositionState get() = LocalCameraPositionState.current @Parcelize -public data class SaveableCameraPositionState( +public data class SaveableCameraPositionData( val position: CameraPosition, val cameraMode: Int ) : Parcelable diff --git a/plugins/src/main/kotlin/extension/KoverExtension.kt b/plugins/src/main/kotlin/extension/KoverExtension.kt index 04a647321e..9cd83f46b4 100644 --- a/plugins/src/main/kotlin/extension/KoverExtension.kt +++ b/plugins/src/main/kotlin/extension/KoverExtension.kt @@ -158,7 +158,6 @@ fun Project.setupKover() { "io.element.android.libraries.designsystem.swipe.SwipeableActionsState", "io.element.android.libraries.designsystem.theme.components.bottomsheet.CustomSheetState", "io.element.android.libraries.maplibre.compose.CameraPositionState", - "io.element.android.libraries.maplibre.compose.SaveableCameraPositionState", "io.element.android.libraries.maplibre.compose.SymbolState", "io.element.android.libraries.matrix.api.room.RoomMembershipState", "io.element.android.libraries.matrix.api.room.RoomMembersState", From d1698034be7198ca3446167b229713f47cc0f4e2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 10 Oct 2025 10:28:01 +0200 Subject: [PATCH 36/38] Let the CI reveal all the error that I do not see locally for compilation cache reasons. --- tools/compose/check_stability.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/compose/check_stability.sh b/tools/compose/check_stability.sh index 06d76ca0ae..7552703281 100755 --- a/tools/compose/check_stability.sh +++ b/tools/compose/check_stability.sh @@ -18,6 +18,7 @@ find . -type f -name "*-classes.txt" | while read -r file; do # Check that there is no line containing "unstable class .*State {" if grep -E 'unstable class .*State \{' "$file"; then echo "❌ ERROR: Found unstable State class in $file" - exit 1 + # TEMPORARY CHANGE + # exit 1 fi done From e57bf354c33e1449337cb51a012f7a3f9d99a9c0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 10 Oct 2025 10:48:29 +0200 Subject: [PATCH 37/38] Remove unused import --- .../impl/timeline/factories/event/TimelineItemEventFactory.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt index 93a5e686d9..dd21271b9f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt @@ -21,7 +21,6 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItemReac import io.element.android.features.messages.impl.timeline.model.TimelineItemReadReceipts import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo import io.element.android.features.messages.impl.utils.messagesummary.MessageSummaryFormatter -import io.element.android.libraries.architecture.map import io.element.android.libraries.core.bool.orTrue import io.element.android.libraries.dateformatter.api.DateFormatter import io.element.android.libraries.dateformatter.api.DateFormatterMode @@ -37,7 +36,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.getDisambigua import io.element.android.libraries.matrix.ui.messages.reply.map import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList -import java.util.Date @AssistedInject class TimelineItemEventFactory( From 339f40e22aaef765bb349209e4ca0deaab667b99 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 10 Oct 2025 11:49:15 +0200 Subject: [PATCH 38/38] Revert "Let the CI reveal all the error that I do not see locally for compilation cache reasons." This reverts commit d1698034be7198ca3446167b229713f47cc0f4e2. --- tools/compose/check_stability.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/compose/check_stability.sh b/tools/compose/check_stability.sh index 7552703281..06d76ca0ae 100755 --- a/tools/compose/check_stability.sh +++ b/tools/compose/check_stability.sh @@ -18,7 +18,6 @@ find . -type f -name "*-classes.txt" | while read -r file; do # Check that there is no line containing "unstable class .*State {" if grep -E 'unstable class .*State \{' "$file"; then echo "❌ ERROR: Found unstable State class in $file" - # TEMPORARY CHANGE - # exit 1 + exit 1 fi done