diff --git a/build.gradle.kts b/build.gradle.kts index e29f7c393b..249c7c2e10 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -376,3 +376,22 @@ subprojects { } } } + +subprojects { + tasks.withType().configureEach { + kotlinOptions { + if (project.findProperty("composeCompilerReports") == "true") { + freeCompilerArgs += listOf( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.buildDir.absolutePath}/compose_compiler" + ) + } + if (project.findProperty("composeCompilerMetrics") == "true") { + freeCompilerArgs += listOf( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.buildDir.absolutePath}/compose_compiler" + ) + } + } + } +} diff --git a/changelog.d/+make-matrix-classes-immutable.misc b/changelog.d/+make-matrix-classes-immutable.misc new file mode 100644 index 0000000000..0dcb7dedb9 --- /dev/null +++ b/changelog.d/+make-matrix-classes-immutable.misc @@ -0,0 +1 @@ +Make most code used in Compose from `:libraries:matrix` and derived classes Immutable or Stable. diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index 1a8ae63645..c7d4d8c9cc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -133,10 +133,10 @@ class MessagesPresenter @AssistedInject constructor( val syncUpdateFlow = room.syncUpdateFlow.collectAsState() val userHasPermissionToSendMessage by room.canSendMessageAsState(type = MessageEventType.ROOM_MESSAGE, updateKey = syncUpdateFlow.value) val userHasPermissionToRedact by room.canRedactAsState(updateKey = syncUpdateFlow.value) - val roomName: Async by remember(roomInfo?.name) { + val roomName: Async by remember { derivedStateOf { roomInfo?.name?.let { Async.Success(it) } ?: Async.Uninitialized } } - val roomAvatar: Async by remember(roomInfo?.avatarUrl) { + val roomAvatar: Async by remember { derivedStateOf { roomInfo?.avatarData()?.let { Async.Success(it) } ?: Async.Uninitialized } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithReplyPreview.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithReplyPreview.kt index 8443ffafa2..8812f9ca8f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithReplyPreview.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithReplyPreview.kt @@ -45,6 +45,8 @@ import io.element.android.libraries.matrix.api.timeline.item.event.PollContent import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.persistentMapOf @PreviewsDayNight @Composable @@ -127,8 +129,8 @@ class InReplyToDetailsProvider : PreviewParameterProvider { question = "Poll which are being replied.", kind = PollKind.Disclosed, maxSelections = 1u, - answers = emptyList(), - votes = emptyMap(), + answers = persistentListOf(), + votes = persistentMapOf(), endTime = null ), ).map { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenter.kt index e75e49c1e3..7c30350cc4 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenter.kt @@ -17,7 +17,6 @@ package io.element.android.features.messages.impl.timeline.components.reactionsummary import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf @@ -38,10 +37,6 @@ class ReactionSummaryPresenter @Inject constructor( ) : Presenter { @Composable override fun present(): ReactionSummaryState { - LaunchedEffect(Unit) { - room.updateMembers() - } - val membersState by room.membersStateFlow.collectAsState() val target: MutableState = remember { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt index 5855bb47a7..2f2709c8aa 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt @@ -92,6 +92,7 @@ import io.element.android.tests.testutils.consumeItemsUntilTimeout import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.waitForPredicate import io.mockk.mockk +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -462,7 +463,7 @@ class MessagesPresenterTest { val room = FakeMatrixRoom(sessionId = A_SESSION_ID) room.givenRoomMembersState( MatrixRoomMembersState.Ready( - listOf( + persistentListOf( aRoomMember(userId = A_SESSION_ID, membership = RoomMembershipState.JOIN), aRoomMember(userId = A_SESSION_ID_2, membership = RoomMembershipState.LEAVE), ) @@ -489,7 +490,7 @@ class MessagesPresenterTest { room.givenRoomMembersState( MatrixRoomMembersState.Error( failure = Throwable(), - prevRoomMembers = listOf( + prevRoomMembers = persistentListOf( aRoomMember(userId = A_SESSION_ID, membership = RoomMembershipState.JOIN), aRoomMember(userId = A_SESSION_ID_2, membership = RoomMembershipState.LEAVE), ) @@ -535,7 +536,7 @@ class MessagesPresenterTest { val room = FakeMatrixRoom(sessionId = A_SESSION_ID) room.givenRoomMembersState( MatrixRoomMembersState.Ready( - listOf( + persistentListOf( aRoomMember(userId = A_SESSION_ID, membership = RoomMembershipState.JOIN), aRoomMember(userId = A_SESSION_ID_2, membership = RoomMembershipState.LEAVE), ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenterTest.kt index b2b75d7e38..ef7891b953 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenterTest.kt @@ -78,11 +78,11 @@ import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.waitForPredicate import io.mockk.mockk +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest -import okhttp3.internal.immutableListOf import org.junit.Rule import org.junit.Test import uniffi.wysiwyg_composer.MentionsState @@ -734,7 +734,7 @@ class MessageComposerPresenterTest { isOneToOne = false, ).apply { givenRoomMembersState(MatrixRoomMembersState.Ready( - immutableListOf(currentUser, invitedUser, bob, david), + persistentListOf(currentUser, invitedUser, bob, david), )) givenCanTriggerRoomNotification(Result.success(true)) } @@ -798,7 +798,7 @@ class MessageComposerPresenterTest { isOneToOne = true, ).apply { givenRoomMembersState(MatrixRoomMembersState.Ready( - immutableListOf(currentUser, invitedUser, bob, david), + persistentListOf(currentUser, invitedUser, bob, david), )) givenCanTriggerRoomNotification(Result.success(true)) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt index 609a264e77..dea1975c6c 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt @@ -55,6 +55,7 @@ import io.element.android.tests.testutils.awaitWithLatch import io.element.android.tests.testutils.consumeItemsUntilPredicate import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.waitForPredicate +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.delay import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest @@ -254,18 +255,18 @@ class TimelinePresenterTest { val (alice, bob, charlie) = aMatrixUserList().take(3).mapIndexed { i, user -> ReactionSender(senderId = user.userId, timestamp = now + i * minuteInMillis) } - val oneReaction = listOf( + val oneReaction = persistentListOf( EventReaction( key = "❤️", - senders = listOf(alice, charlie) + senders = persistentListOf(alice, charlie) ), EventReaction( key = "👍", - senders = listOf(alice, bob) + senders = persistentListOf(alice, bob) ), EventReaction( key = "🐶", - senders = listOf(charlie) + senders = persistentListOf(charlie) ), ) timeline.updateTimelineItems { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenterTests.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenterTests.kt index 080dfaeba6..9d70e03fcd 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenterTests.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenterTests.kt @@ -29,6 +29,7 @@ import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.tests.testutils.WarmUpRule +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -42,7 +43,7 @@ class ReactionSummaryPresenterTests { private val roomMember = aRoomMember(userId = A_USER_ID, avatarUrl = AN_AVATAR_URL, displayName = A_USER_NAME) private val summaryEvent = ReactionSummaryEvents.ShowReactionSummary(AN_EVENT_ID, listOf(aggregatedReaction), aggregatedReaction.key) private val room = FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember))) + givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(roomMember))) } private val presenter = ReactionSummaryPresenter(room) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt index ab2e429d10..a397acafcd 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt @@ -55,6 +55,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageT import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractorWithoutValidation +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.test.runTest import org.junit.Test @@ -280,7 +281,7 @@ class TimelineItemContentMessageFactoryTest { ), details = AudioDetails( duration = 1.minutes, - waveform = listOf(1f, 2f), + waveform = persistentListOf(1f, 2f), ), ) ), @@ -293,7 +294,7 @@ class TimelineItemContentMessageFactoryTest { duration = 1.minutes, mediaSource = MediaSource(url = "url", json = null), mimeType = MimeTypes.Ogg, - waveform = listOf(1f, 2f).toImmutableList() + waveform = persistentListOf(1f, 2f) ) assertThat(result).isEqualTo(expected) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactoryTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactoryTest.kt index d6673b4770..2ae88288ae 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactoryTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactoryTest.kt @@ -38,6 +38,11 @@ import io.element.android.libraries.matrix.test.A_USER_ID_7 import io.element.android.libraries.matrix.test.A_USER_ID_8 import io.element.android.libraries.matrix.test.A_USER_ID_9 import io.element.android.libraries.matrix.test.FakeMatrixClient +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.ImmutableMap +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.persistentMapOf +import kotlinx.collections.immutable.toImmutableMap import kotlinx.coroutines.test.runTest import org.junit.Test @@ -55,7 +60,7 @@ internal class TimelineItemContentPollFactoryTest { @Test fun `Disclosed poll - not ended, some votes, including one from current user`() = runTest { - val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id } + val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() Truth.assertThat( factory.create(aPollContent(votes = votes), eventId = null) ) @@ -87,7 +92,7 @@ internal class TimelineItemContentPollFactoryTest { @Test fun `Disclosed poll - ended, some votes, including one from current user (winner)`() = runTest { - val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id } + val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() Truth.assertThat( factory.create(aPollContent(votes = votes, endTime = 1UL), eventId = null) ) @@ -106,7 +111,7 @@ internal class TimelineItemContentPollFactoryTest { @Test fun `Disclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest { - val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id } + val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() Truth.assertThat( factory.create(aPollContent(votes = votes, endTime = 1UL), eventId = null) ) @@ -136,7 +141,7 @@ internal class TimelineItemContentPollFactoryTest { @Test fun `Undisclosed poll - not ended, some votes, including one from current user`() = runTest { - val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id } + val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() Truth.assertThat( factory.create(aPollContent(pollKind = PollKind.Undisclosed, votes = votes), eventId = null) ) @@ -172,7 +177,7 @@ internal class TimelineItemContentPollFactoryTest { @Test fun `Undisclosed poll - ended, some votes, including one from current user (winner)`() = runTest { - val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id } + val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() Truth.assertThat( factory.create(aPollContent(pollKind = PollKind.Undisclosed, votes = votes, endTime = 1UL), eventId = null) ) @@ -192,7 +197,7 @@ internal class TimelineItemContentPollFactoryTest { @Test fun `Undisclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest { - val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id } + val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() Truth.assertThat( factory.create(aPollContent(PollKind.Undisclosed).copy(votes = votes, endTime = 1UL), eventId = null) ) @@ -221,13 +226,13 @@ internal class TimelineItemContentPollFactoryTest { private fun aPollContent( pollKind: PollKind = PollKind.Disclosed, - votes: Map> = emptyMap(), + votes: ImmutableMap> = persistentMapOf(), endTime: ULong? = null, ): PollContent = PollContent( question = A_POLL_QUESTION, kind = pollKind, maxSelections = 1UL, - answers = listOf(A_POLL_ANSWER_1, A_POLL_ANSWER_2, A_POLL_ANSWER_3, A_POLL_ANSWER_4), + answers = persistentListOf(A_POLL_ANSWER_1, A_POLL_ANSWER_2, A_POLL_ANSWER_3, A_POLL_ANSWER_4), votes = votes, endTime = endTime, ) @@ -275,17 +280,17 @@ internal class TimelineItemContentPollFactoryTest { private val A_POLL_ANSWER_3 = PollAnswer("id_3", "French Fries") private val A_POLL_ANSWER_4 = PollAnswer("id_4", "Hamburger") - private val MY_USER_WINNING_VOTES = mapOf( - A_POLL_ANSWER_1 to listOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4), - A_POLL_ANSWER_2 to listOf(A_USER_ID /* my vote */, A_USER_ID_5, A_USER_ID_6, A_USER_ID_7, A_USER_ID_8, A_USER_ID_9), // winner - A_POLL_ANSWER_3 to emptyList(), - A_POLL_ANSWER_4 to listOf(A_USER_ID_10), + private val MY_USER_WINNING_VOTES = persistentMapOf( + A_POLL_ANSWER_1 to persistentListOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4), + A_POLL_ANSWER_2 to persistentListOf(A_USER_ID /* my vote */, A_USER_ID_5, A_USER_ID_6, A_USER_ID_7, A_USER_ID_8, A_USER_ID_9), // winner + A_POLL_ANSWER_3 to persistentListOf(), + A_POLL_ANSWER_4 to persistentListOf(A_USER_ID_10), ) - private val OTHER_WINNING_VOTES = mapOf( - A_POLL_ANSWER_1 to listOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4, A_USER_ID_5), // winner - A_POLL_ANSWER_2 to listOf(A_USER_ID /* my vote */, A_USER_ID_6), - A_POLL_ANSWER_3 to emptyList(), - A_POLL_ANSWER_4 to listOf(A_USER_ID_7, A_USER_ID_8, A_USER_ID_9, A_USER_ID_10), // winner + private val OTHER_WINNING_VOTES = persistentMapOf( + A_POLL_ANSWER_1 to persistentListOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4, A_USER_ID_5), // winner + A_POLL_ANSWER_2 to persistentListOf(A_USER_ID /* my vote */, A_USER_ID_6), + A_POLL_ANSWER_3 to persistentListOf(), + A_POLL_ANSWER_4 to persistentListOf(A_USER_ID_7, A_USER_ID_8, A_USER_ID_9, A_USER_ID_10), // winner ) } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt index 8e776d1eea..3a003e23a9 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt @@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.mediaplayer.api.MediaPlayer import io.element.android.libraries.mediaplayer.test.FakeMediaPlayer import io.element.android.tests.testutils.testCoroutineDispatchers +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Test @@ -88,8 +89,8 @@ fun aRedactedMatrixTimeline(eventId: EventId) = listOf( isOwn = false, isRemote = false, localSendState = null, - reactions = listOf(), - receipts = listOf(), + reactions = persistentListOf(), + receipts = persistentListOf(), sender = A_USER_ID, senderProfile = ProfileTimelineDetails.Unavailable, timestamp = 9442, diff --git a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenterTest.kt b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenterTest.kt index ae54c6a1e5..8cb55704d5 100644 --- a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenterTest.kt +++ b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenterTest.kt @@ -39,6 +39,7 @@ import io.element.android.libraries.matrix.test.room.anEventTimelineItem import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.WarmUpRule +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.delay import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -539,7 +540,7 @@ class CreatePollPresenterTest { private fun anExistingPoll() = aPollContent( question = "Do you like polls?", - answers = listOf( + answers = persistentListOf( PollAnswer("1", "Yes"), PollAnswer("2", "No"), PollAnswer("2", "Maybe"), diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt index 5d8b149676..1be23be3f6 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt @@ -33,6 +33,7 @@ import io.element.android.libraries.matrix.api.notificationsettings.Notification import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomSummary +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.debounce @@ -84,7 +85,7 @@ class EditDefaultNotificationSettingPresenter @AssistedInject constructor( return EditDefaultNotificationSettingState( isOneToOne = isOneToOne, mode = mode.value, - roomsWithUserDefinedMode = roomsWithUserDefinedMode.value, + roomsWithUserDefinedMode = roomsWithUserDefinedMode.value.toImmutableList(), changeNotificationSettingAction = changeNotificationSettingAction.value, eventSink = ::handleEvents ) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingState.kt index e8590ec27f..60e8dfd10a 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingState.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingState.kt @@ -19,11 +19,12 @@ package io.element.android.features.preferences.impl.notifications.edit import io.element.android.libraries.architecture.Async import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.roomlist.RoomSummary +import kotlinx.collections.immutable.ImmutableList data class EditDefaultNotificationSettingState( val isOneToOne: Boolean, val mode: RoomNotificationMode?, - val roomsWithUserDefinedMode: List, + val roomsWithUserDefinedMode: ImmutableList, val changeNotificationSettingAction: Async, val eventSink: (EditDefaultNotificationSettingStateEvents) -> Unit, ) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt index 71fbfb1e1b..e706701f8d 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt @@ -22,6 +22,7 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails +import kotlinx.collections.immutable.persistentListOf open class EditDefaultNotificationSettingStateProvider: PreviewParameterProvider { override val values: Sequence @@ -39,7 +40,7 @@ private fun anEditDefaultNotificationSettingsState( ) = EditDefaultNotificationSettingState( isOneToOne = isOneToOne, mode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, - roomsWithUserDefinedMode = listOf(aRoomSummary()), + roomsWithUserDefinedMode = persistentListOf(aRoomSummary()), changeNotificationSettingAction = changeNotificationSettingAction, eventSink = {} ) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt index f1e6447a10..4954af8efc 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt @@ -90,7 +90,7 @@ fun aRoomMember( isIgnored = isIgnored, ) -fun aRoomMemberList() = listOf( +fun aRoomMemberList() = persistentListOf( anAlice(), aBob(), aRoomMember(UserId("@carol:server.org"), "Carol"), diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt index 5ab79d2cee..f7a74ddcc0 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt @@ -48,6 +48,7 @@ import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.tests.testutils.consumeItemsUntilPredicate import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.WarmUpRule +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -127,7 +128,7 @@ class RoomDetailsPresenterTests { isEncrypted = true, isDirect = true, ).apply { - val roomMembers = listOf(myRoomMember, otherRoomMember) + val roomMembers = persistentListOf(myRoomMember, otherRoomMember) givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers)) } val presenter = createRoomDetailsPresenter(room, dispatchers = testCoroutineDispatchers()) @@ -218,7 +219,7 @@ class RoomDetailsPresenterTests { isEncrypted = true, isDirect = true, ).apply { - val roomMembers = listOf(myRoomMember, otherRoomMember) + val roomMembers = persistentListOf(myRoomMember, otherRoomMember) givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers)) givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.success(true)) @@ -250,7 +251,7 @@ class RoomDetailsPresenterTests { isDirect = true, topic = null, ).apply { - val roomMembers = listOf(myRoomMember, otherRoomMember) + val roomMembers = persistentListOf(myRoomMember, otherRoomMember) givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers)) givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.success(true)) diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt index 4033038b69..9763ed280b 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt @@ -39,6 +39,7 @@ import io.element.android.libraries.usersearch.test.FakeUserRepository import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -167,7 +168,7 @@ internal class RoomInviteMembersPresenterTest { matrixRoom = FakeMatrixRoom().apply { givenRoomMembersState( MatrixRoomMembersState.Ready( - listOf( + persistentListOf( aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), ) @@ -227,7 +228,7 @@ internal class RoomInviteMembersPresenterTest { roomMemberListDataSource = createDataSource(FakeMatrixRoom().apply { givenRoomMembersState( MatrixRoomMembersState.Ready( - listOf( + persistentListOf( aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), ) diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt index a249e38823..0921efe0ca 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt @@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.tests.testutils.WarmUpRule +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -47,7 +48,7 @@ class RoomMemberDetailsPresenterTests { val room = aMatrixRoom().apply { givenUserDisplayNameResult(Result.success("A custom name")) givenUserAvatarUrlResult(Result.success("A custom avatar")) - givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember))) + givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(roomMember))) } val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId) moleculeFlow(RecompositionMode.Immediate) { @@ -71,7 +72,7 @@ class RoomMemberDetailsPresenterTests { val room = aMatrixRoom().apply { givenUserDisplayNameResult(Result.failure(Throwable())) givenUserAvatarUrlResult(Result.failure(Throwable())) - givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember))) + givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(roomMember))) } val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId) moleculeFlow(RecompositionMode.Immediate) { @@ -91,7 +92,7 @@ class RoomMemberDetailsPresenterTests { val room = aMatrixRoom().apply { givenUserDisplayNameResult(Result.success(null)) givenUserAvatarUrlResult(Result.success(null)) - givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember))) + givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(roomMember))) } val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId) moleculeFlow(RecompositionMode.Immediate) { diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt index 3a445e6cdc..cfaf9b8321 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt @@ -23,7 +23,7 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.room.RoomNotificationMode @Immutable -data class RoomListRoomSummary constructor( +data class RoomListRoomSummary( val id: String, val roomId: RoomId, val name: String = "", diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTests.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTests.kt index 403324816f..8f8795ed78 100644 --- a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTests.kt +++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTests.kt @@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.api.verification.VerificationEmoji import io.element.android.libraries.matrix.api.verification.VerificationFlowState import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService import io.element.android.tests.testutils.WarmUpRule +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -132,7 +133,7 @@ class VerifySelfSessionPresenterTests { presenter.present() }.test { requestVerificationAndAwaitVerifyingState(service) - service.givenVerificationFlowState(VerificationFlowState.ReceivedVerificationData(emptyList())) + service.givenVerificationFlowState(VerificationFlowState.ReceivedVerificationData(persistentListOf())) ensureAllEventsConsumed() } } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/BackupUploadState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/BackupUploadState.kt index 61130c43db..7e349216f4 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/BackupUploadState.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/BackupUploadState.kt @@ -16,6 +16,9 @@ package io.element.android.libraries.matrix.api.encryption +import androidx.compose.runtime.Immutable + +@Immutable sealed interface BackupUploadState { data object Unknown : BackupUploadState diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/SteadyStateException.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/SteadyStateException.kt index 1e83344a02..88525caac2 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/SteadyStateException.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/SteadyStateException.kt @@ -16,6 +16,9 @@ package io.element.android.libraries.matrix.api.encryption +import androidx.compose.runtime.Immutable + +@Immutable sealed interface SteadyStateException { /** * The backup can be deleted. diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioDetails.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioDetails.kt index d8ddca14e7..d3ff0e9f83 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioDetails.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioDetails.kt @@ -16,9 +16,10 @@ package io.element.android.libraries.matrix.api.media +import kotlinx.collections.immutable.ImmutableList import kotlin.time.Duration data class AudioDetails( val duration: Duration, - val waveform: List, + val waveform: ImmutableList, ) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/permalink/PermalinkData.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/permalink/PermalinkData.kt index 72caa711cb..e1036011f6 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/permalink/PermalinkData.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/permalink/PermalinkData.kt @@ -17,18 +17,21 @@ package io.element.android.libraries.matrix.api.permalink import android.net.Uri +import androidx.compose.runtime.Immutable +import kotlinx.collections.immutable.ImmutableList /** * This sealed class represents all the permalink cases. * You don't have to instantiate yourself but should use [PermalinkParser] instead. */ +@Immutable sealed interface PermalinkData { data class RoomLink( val roomIdOrAlias: String, val isRoomAlias: Boolean, val eventId: String?, - val viaParameters: List + val viaParameters: ImmutableList ) : PermalinkData /* diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/permalink/PermalinkParser.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/permalink/PermalinkParser.kt index 4a89d05276..dcd5221de8 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/permalink/PermalinkParser.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/permalink/PermalinkParser.kt @@ -19,6 +19,7 @@ package io.element.android.libraries.matrix.api.permalink import android.net.Uri import android.net.UrlQuerySanitizer import io.element.android.libraries.matrix.api.core.MatrixPatterns +import kotlinx.collections.immutable.toImmutableList import timber.log.Timber import java.net.URLDecoder @@ -80,7 +81,7 @@ object PermalinkParser { roomIdOrAlias = decodedIdentifier, isRoomAlias = true, eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }, - viaParameters = viaQueryParameters + viaParameters = viaQueryParameters.toImmutableList() ) } else -> PermalinkData.FallbackLink(uri, MatrixPatterns.isGroupId(identifier)) @@ -119,7 +120,7 @@ object PermalinkParser { roomIdOrAlias = identifier, isRoomAlias = false, eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }, - viaParameters = viaQueryParameters + viaParameters = viaQueryParameters.toImmutableList() ) } } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt index 6690387b04..1304ca40a8 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt @@ -16,8 +16,11 @@ package io.element.android.libraries.matrix.api.room +import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem +import kotlinx.collections.immutable.ImmutableList +@Immutable data class MatrixRoomInfo( val id: String, val name: String?, @@ -28,7 +31,7 @@ data class MatrixRoomInfo( val isSpace: Boolean, val isTombstoned: Boolean, val canonicalAlias: String?, - val alternativeAliases: List, + val alternativeAliases: ImmutableList, val currentUserMembership: CurrentUserMembership, val latestEvent: EventTimelineItem?, val inviter: RoomMember?, @@ -39,5 +42,5 @@ data class MatrixRoomInfo( val notificationCount: Long, val userDefinedNotificationMode: RoomNotificationMode?, val hasRoomCall: Boolean, - val activeRoomCallParticipants: List + val activeRoomCallParticipants: ImmutableList ) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomMembersState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomMembersState.kt index 5597aaf1c5..9a25aaa12e 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomMembersState.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomMembersState.kt @@ -17,13 +17,14 @@ package io.element.android.libraries.matrix.api.room import androidx.compose.runtime.Immutable +import kotlinx.collections.immutable.ImmutableList @Immutable sealed interface MatrixRoomMembersState { data object Unknown : MatrixRoomMembersState - data class Pending(val prevRoomMembers: List? = null) : MatrixRoomMembersState - data class Error(val failure: Throwable, val prevRoomMembers: List? = null) : MatrixRoomMembersState - data class Ready(val roomMembers: List) : MatrixRoomMembersState + data class Pending(val prevRoomMembers: ImmutableList? = null) : MatrixRoomMembersState + data class Error(val failure: Throwable, val prevRoomMembers: ImmutableList? = null) : MatrixRoomMembersState + data class Ready(val roomMembers: ImmutableList) : MatrixRoomMembersState } fun MatrixRoomMembersState.roomMembers(): List? { diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListService.kt index 9897c2cff5..ca38128e5d 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListService.kt @@ -16,6 +16,7 @@ package io.element.android.libraries.matrix.api.roomlist +import androidx.compose.runtime.Immutable import kotlinx.coroutines.flow.StateFlow /** @@ -25,6 +26,7 @@ import kotlinx.coroutines.flow.StateFlow */ interface RoomListService { + @Immutable sealed interface State { data object Idle : State data object Running : State @@ -32,6 +34,7 @@ interface RoomListService { data object Terminated : State } + @Immutable sealed interface SyncIndicator { data object Show : SyncIndicator data object Hide : SyncIndicator diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt index f63953e260..8a8d087e8f 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt @@ -16,11 +16,15 @@ package io.element.android.libraries.matrix.api.timeline.item.event +import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.poll.PollAnswer import io.element.android.libraries.matrix.api.poll.PollKind +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.ImmutableMap +@Immutable sealed interface EventContent data class MessageContent( @@ -43,14 +47,16 @@ data class PollContent( val question: String, val kind: PollKind, val maxSelections: ULong, - val answers: List, - val votes: Map>, + val answers: ImmutableList, + val votes: ImmutableMap>, val endTime: ULong? ) : EventContent data class UnableToDecryptContent( val data: Data ) : EventContent { + + @Immutable sealed interface Data { data class OlmV1Curve25519AesSha2( val senderKey: String 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 a2e68d17d2..65fc5a06a9 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 @@ -16,7 +16,11 @@ 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: List + val senders: ImmutableList ) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt index 9f38ce9441..fa15f8f096 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt @@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo +import kotlinx.collections.immutable.ImmutableList data class EventTimelineItem( val eventId: EventId?, @@ -29,8 +30,8 @@ data class EventTimelineItem( val isOwn: Boolean, val isRemote: Boolean, val localSendState: LocalEventSendState?, - val reactions: List, - val receipts: List, + val reactions: ImmutableList, + val receipts: ImmutableList, val sender: UserId, val senderProfile: ProfileTimelineDetails, val timestamp: Long, diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/InReplyTo.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/InReplyTo.kt index 14a84e2a90..6965ed9f1e 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/InReplyTo.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/InReplyTo.kt @@ -16,9 +16,11 @@ package io.element.android.libraries.matrix.api.timeline.item.event +import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UserId +@Immutable sealed interface InReplyTo { /** The event details are not loaded yet. We can fetch them. */ data class NotLoaded(val eventId: EventId) : InReplyTo diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/LocalEventSendState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/LocalEventSendState.kt index 265be8af79..f74ddca3a8 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/LocalEventSendState.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/LocalEventSendState.kt @@ -16,8 +16,10 @@ package io.element.android.libraries.matrix.api.timeline.item.event +import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.core.EventId +@Immutable sealed interface LocalEventSendState { data object NotSentYet : LocalEventSendState data object Canceled : LocalEventSendState diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/MessageType.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/MessageType.kt index 14c2302def..0b2d948c4e 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/MessageType.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/MessageType.kt @@ -16,6 +16,7 @@ package io.element.android.libraries.matrix.api.timeline.item.event +import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.media.AudioDetails import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.FileInfo @@ -23,6 +24,7 @@ import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.media.VideoInfo +@Immutable sealed interface MessageType data class EmoteMessageType( diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/OtherState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/OtherState.kt index 2cbfaf76b4..6960b3565d 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/OtherState.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/OtherState.kt @@ -16,6 +16,9 @@ package io.element.android.libraries.matrix.api.timeline.item.event +import androidx.compose.runtime.Immutable + +@Immutable sealed interface OtherState { data object PolicyRuleRoom : OtherState data object PolicyRuleServer : OtherState diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/ProfileTimelineDetails.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/ProfileTimelineDetails.kt index eddb9eb169..44664a256a 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/ProfileTimelineDetails.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/ProfileTimelineDetails.kt @@ -16,6 +16,9 @@ package io.element.android.libraries.matrix.api.timeline.item.event +import androidx.compose.runtime.Immutable + +@Immutable sealed interface ProfileTimelineDetails { data object Unavailable : ProfileTimelineDetails diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/MatrixSearchUserResults.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/MatrixSearchUserResults.kt index a63a31b51f..a7985c864f 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/MatrixSearchUserResults.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/user/MatrixSearchUserResults.kt @@ -16,7 +16,9 @@ package io.element.android.libraries.matrix.api.user +import kotlinx.collections.immutable.ImmutableList + data class MatrixSearchUserResults( - val results: List, + val results: ImmutableList, val limited: Boolean, ) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt index c463530050..639b704823 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt @@ -16,6 +16,8 @@ package io.element.android.libraries.matrix.api.verification +import androidx.compose.runtime.Immutable +import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow @@ -75,6 +77,7 @@ interface SessionVerificationService { } /** Verification status of the current session. */ +@Immutable sealed interface SessionVerifiedStatus { /** Unknown status, we couldn't read the actual value from the SDK. */ data object Unknown : SessionVerifiedStatus @@ -87,6 +90,7 @@ sealed interface SessionVerifiedStatus { } /** States produced by the [SessionVerificationService]. */ +@Immutable sealed interface VerificationFlowState { /** Initial state. */ data object Initial : VerificationFlowState @@ -98,7 +102,7 @@ sealed interface VerificationFlowState { data object StartedSasVerification : VerificationFlowState /** Verification data for the SAS verification (emojis) received. */ - data class ReceivedVerificationData(val emoji: List) : VerificationFlowState + data class ReceivedVerificationData(val emoji: ImmutableList) : VerificationFlowState /** Verification completed successfully. */ data object Finished : VerificationFlowState diff --git a/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/permalink/PermalinkParserTest.kt b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/permalink/PermalinkParserTest.kt index d55b6aebbe..590be150c4 100644 --- a/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/permalink/PermalinkParserTest.kt +++ b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/permalink/PermalinkParserTest.kt @@ -17,6 +17,7 @@ package io.element.android.libraries.matrix.api.permalink import com.google.common.truth.Truth.assertThat +import kotlinx.collections.immutable.persistentListOf import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @@ -66,7 +67,7 @@ class PermalinkParserTest { roomIdOrAlias = "!aBCD1234:matrix.org", isRoomAlias = false, eventId = null, - viaParameters = emptyList(), + viaParameters = persistentListOf(), ) ) } @@ -79,7 +80,7 @@ class PermalinkParserTest { roomIdOrAlias = "!aBCD1234:matrix.org", isRoomAlias = false, eventId = "\$1234567890abcdef:matrix.org", - viaParameters = emptyList(), + viaParameters = persistentListOf(), ) ) } @@ -92,7 +93,7 @@ class PermalinkParserTest { roomIdOrAlias = "!aBCD1234:matrix.org", isRoomAlias = false, eventId = null, - viaParameters = emptyList(), + viaParameters = persistentListOf(), ) ) } @@ -105,7 +106,7 @@ class PermalinkParserTest { roomIdOrAlias = "!aBCD1234:matrix.org", isRoomAlias = false, eventId = "\$1234567890abcdef:matrix.org", - viaParameters = listOf("matrix.org", "matrix.com"), + viaParameters = persistentListOf("matrix.org", "matrix.com"), ) ) } @@ -118,7 +119,7 @@ class PermalinkParserTest { roomIdOrAlias = "#element-android:matrix.org", isRoomAlias = true, eventId = null, - viaParameters = emptyList(), + viaParameters = persistentListOf(), ) ) } diff --git a/libraries/matrix/impl/build.gradle.kts b/libraries/matrix/impl/build.gradle.kts index 81b5f70a11..ef590c6889 100644 --- a/libraries/matrix/impl/build.gradle.kts +++ b/libraries/matrix/impl/build.gradle.kts @@ -47,6 +47,7 @@ dependencies { implementation("net.java.dev.jna:jna:5.13.0@aar") implementation(libs.androidx.datastore.preferences) implementation(libs.serialization.json) + implementation(libs.kotlinx.collections.immutable) testImplementation(libs.test.junit) testImplementation(libs.test.truth) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioDetails.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioDetails.kt index 2540372260..2bdcf6de0f 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioDetails.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioDetails.kt @@ -17,13 +17,14 @@ package io.element.android.libraries.matrix.impl.media import io.element.android.libraries.matrix.api.media.AudioDetails +import kotlinx.collections.immutable.toImmutableList import kotlin.time.toJavaDuration import kotlin.time.toKotlinDuration import org.matrix.rustcomponents.sdk.UnstableAudioDetailsContent as RustAudioDetails fun RustAudioDetails.map(): AudioDetails = AudioDetails( duration = duration.toKotlinDuration(), - waveform = waveform.fromMSC3246range(), + waveform = waveform.fromMSC3246range().toImmutableList(), ) fun AudioDetails.map(): RustAudioDetails = RustAudioDetails( diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt index c24d996714..3ea1895e22 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt @@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.MatrixRoomInfo import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper +import kotlinx.collections.immutable.toImmutableList import org.matrix.rustcomponents.sdk.use import org.matrix.rustcomponents.sdk.Membership as RustMembership import org.matrix.rustcomponents.sdk.RoomInfo as RustRoomInfo @@ -40,7 +41,7 @@ class MatrixRoomInfoMapper( isSpace = it.isSpace, isTombstoned = it.isTombstoned, canonicalAlias = it.canonicalAlias, - alternativeAliases = it.alternativeAliases, + alternativeAliases = it.alternativeAliases.toImmutableList(), currentUserMembership = it.membership.map(), latestEvent = it.latestEvent?.use (timelineItemMapper::map), inviter = it.inviter?.use(RoomMemberMapper::map), @@ -51,7 +52,7 @@ class MatrixRoomInfoMapper( notificationCount = it.notificationCount.toLong(), userDefinedNotificationMode = it.userDefinedNotificationMode?.map(), hasRoomCall = it.hasRoomCall, - activeRoomCallParticipants = it.activeRoomCallParticipants + activeRoomCallParticipants = it.activeRoomCallParticipants.toImmutableList() ) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt index 6d8578ac0c..bef5e7bce4 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt @@ -57,6 +57,7 @@ import io.element.android.libraries.matrix.impl.widget.RustWidgetDriver import io.element.android.libraries.matrix.impl.widget.generateWidgetWebViewUrl import io.element.android.libraries.sessionstorage.api.SessionData import io.element.android.services.toolbox.api.systemclock.SystemClock +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -198,7 +199,7 @@ class RustMatrixRoom( override suspend fun updateMembers(): Result = withContext(roomMembersDispatcher) { val currentState = _membersStateFlow.value - val currentMembers = currentState.roomMembers() + val currentMembers = currentState.roomMembers()?.toImmutableList() _membersStateFlow.value = MatrixRoomMembersState.Pending(prevRoomMembers = currentMembers) var rustMembers: List? = null try { @@ -213,7 +214,7 @@ class RustMatrixRoom( } } val mappedMembers = rustMembers.parallelMap(RoomMemberMapper::map) - _membersStateFlow.value = MatrixRoomMembersState.Ready(mappedMembers) + _membersStateFlow.value = MatrixRoomMembersState.Ready(mappedMembers.toImmutableList()) Result.success(Unit) } catch (exception: CancellationException) { _membersStateFlow.value = MatrixRoomMembersState.Error(prevRoomMembers = currentMembers, failure = exception) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt index d761e91d6c..4e965fc4ef 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt @@ -27,6 +27,9 @@ import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimeli import io.element.android.libraries.matrix.api.timeline.item.event.ReactionSender import io.element.android.libraries.matrix.api.timeline.item.event.Receipt import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import org.matrix.rustcomponents.sdk.Reaction import org.matrix.rustcomponents.sdk.EventItemOrigin as RustEventItemOrigin import org.matrix.rustcomponents.sdk.EventSendState as RustEventSendState @@ -81,7 +84,7 @@ fun RustEventSendState?.map(): LocalEventSendState? { } } -private fun List?.map(): List { +private fun List?.map(): ImmutableList { return this?.map { EventReaction( key = it.key, @@ -90,18 +93,20 @@ private fun List?.map(): List { senderId = UserId(sender.senderId), timestamp = sender.timestamp.toLong() ) - } + }.toImmutableList() ) - } ?: emptyList() + }?.toImmutableList() ?: persistentListOf() } -private fun Map.map(): List { +private fun Map.map(): ImmutableList { return map { - Receipt( - userId = UserId(it.key), - timestamp = it.value.timestamp?.toLong() ?: 0 - ) - }.sortedByDescending { it.timestamp } + Receipt( + userId = UserId(it.key), + timestamp = it.value.timestamp?.toLong() ?: 0 + ) + } + .sortedByDescending { it.timestamp } + .toImmutableList() } private fun RustEventTimelineItemDebugInfo.map(): TimelineItemDebugInfo { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt index 01dd32c048..7bad7a34d2 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt @@ -32,6 +32,8 @@ import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecry import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent import io.element.android.libraries.matrix.impl.media.map import io.element.android.libraries.matrix.impl.poll.map +import kotlinx.collections.immutable.toImmutableList +import kotlinx.collections.immutable.toImmutableMap import org.matrix.rustcomponents.sdk.TimelineItemContent import org.matrix.rustcomponents.sdk.TimelineItemContentKind import org.matrix.rustcomponents.sdk.use @@ -106,10 +108,10 @@ class TimelineEventContentMapper(private val eventMessageMapper: EventMessageMap question = kind.question, kind = kind.kind.map(), maxSelections = kind.maxSelections, - answers = kind.answers.map { answer -> answer.map() }, + answers = kind.answers.map { answer -> answer.map() }.toImmutableList(), votes = kind.votes.mapValues { vote -> - vote.value.map { userId -> UserId(userId) } - }, + vote.value.map { userId -> UserId(userId) }.toImmutableList() + }.toImmutableMap(), endTime = kind.endTime, ) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/usersearch/UserSearchResultMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/usersearch/UserSearchResultMapper.kt index 1ec0b512ec..b95cbaeed1 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/usersearch/UserSearchResultMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/usersearch/UserSearchResultMapper.kt @@ -17,13 +17,14 @@ package io.element.android.libraries.matrix.impl.usersearch import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults +import kotlinx.collections.immutable.toImmutableList import org.matrix.rustcomponents.sdk.SearchUsersResults object UserSearchResultMapper { fun map(result: SearchUsersResults): MatrixSearchUserResults { return MatrixSearchUserResults( - results = result.results.map(UserProfileMapper::map), + results = result.results.map(UserProfileMapper::map).toImmutableList(), limited = result.limited, ) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt index a4dfadfa5b..3d00c2d50e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt @@ -23,6 +23,7 @@ import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatu import io.element.android.libraries.matrix.api.verification.VerificationEmoji import io.element.android.libraries.matrix.api.verification.VerificationFlowState import io.element.android.libraries.matrix.impl.sync.RustSyncService +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -106,8 +107,9 @@ class RustSessionVerificationService( override fun didReceiveVerificationData(data: List) { val emojis = data.map { emoji -> - emoji.use { VerificationEmoji(it.symbol(), it.description()) } - } + emoji.use { VerificationEmoji(it.symbol(), it.description()) } + } + .toImmutableList() _verificationFlowState.value = VerificationFlowState.ReceivedVerificationData(emojis) } diff --git a/libraries/matrix/test/build.gradle.kts b/libraries/matrix/test/build.gradle.kts index 4e8893aab6..9c41948bd7 100644 --- a/libraries/matrix/test/build.gradle.kts +++ b/libraries/matrix/test/build.gradle.kts @@ -28,4 +28,5 @@ dependencies { api(libs.coroutines.core) implementation(libs.coroutines.test) implementation(projects.tests.testutils) + implementation(libs.kotlinx.collections.immutable) } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt index 17c351945f..67c150fa3f 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt @@ -53,6 +53,7 @@ import io.element.android.libraries.matrix.test.notificationsettings.FakeNotific import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline import io.element.android.libraries.matrix.test.widget.FakeWidgetDriver import io.element.android.tests.testutils.simulateLongTask +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -615,7 +616,7 @@ fun aRoomInfo( isSpace = isSpace, isTombstoned = isTombstoned, canonicalAlias = canonicalAlias, - alternativeAliases = alternativeAliases, + alternativeAliases = alternativeAliases.toImmutableList(), currentUserMembership = currentUserMembership, latestEvent = latestEvent, inviter = inviter, @@ -626,5 +627,5 @@ fun aRoomInfo( notificationCount = notificationCount, userDefinedNotificationMode = userDefinedNotificationMode, hasRoomCall = hasRoomCall, - activeRoomCallParticipants = activeRoomCallParticipants + activeRoomCallParticipants = activeRoomCallParticipants.toImmutableList(), ) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt index 3c7b3eb594..2ff8ef1745 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt @@ -44,6 +44,9 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_NAME +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.persistentMapOf fun aRoomSummaryFilled( roomId: RoomId = A_ROOM_ID, @@ -107,8 +110,8 @@ fun anEventTimelineItem( isOwn: Boolean = false, isRemote: Boolean = false, localSendState: LocalEventSendState? = null, - reactions: List = emptyList(), - receipts: List = emptyList(), + reactions: ImmutableList = persistentListOf(), + receipts: ImmutableList = persistentListOf(), sender: UserId = A_USER_ID, senderProfile: ProfileTimelineDetails = aProfileTimelineDetails(), timestamp: Long = 0L, @@ -181,12 +184,12 @@ fun aTimelineItemDebugInfo( fun aPollContent( question: String = "Do you like polls?", - answers: List = listOf(PollAnswer("1", "Yes"), PollAnswer("2", "No")), + answers: ImmutableList = persistentListOf(PollAnswer("1", "Yes"), PollAnswer("2", "No")), ) = PollContent( question = question, kind = PollKind.Disclosed, maxSelections = 1u, answers = answers, - votes = mapOf(), + votes = persistentMapOf(), endTime = null ) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt index 62b0b39adf..34405f1e3d 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt @@ -20,6 +20,8 @@ import io.element.android.libraries.matrix.api.verification.SessionVerificationS import io.element.android.libraries.matrix.api.verification.VerificationFlowState import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.matrix.api.verification.VerificationEmoji +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -29,7 +31,7 @@ class FakeSessionVerificationService : SessionVerificationService { private val _sessionVerifiedStatus = MutableStateFlow(SessionVerifiedStatus.Unknown) private var _verificationFlowState = MutableStateFlow(VerificationFlowState.Initial) private var _canVerifySessionFlow = MutableStateFlow(true) - private var emojiList = emptyList() + private var emojiList = persistentListOf() var shouldFail = false override val verificationFlowState: StateFlow =_verificationFlowState @@ -87,7 +89,7 @@ class FakeSessionVerificationService : SessionVerificationService { } fun givenEmojiList(emojis: List) { - this.emojiList = emojis + this.emojiList = emojis.toPersistentList() } override suspend fun reset() { diff --git a/libraries/usersearch/impl/build.gradle.kts b/libraries/usersearch/impl/build.gradle.kts index 226860e86f..f1d936f1c7 100644 --- a/libraries/usersearch/impl/build.gradle.kts +++ b/libraries/usersearch/impl/build.gradle.kts @@ -34,6 +34,7 @@ dependencies { implementation(projects.libraries.matrixui) implementation(projects.libraries.matrix.api) api(projects.libraries.usersearch.api) + implementation(libs.kotlinx.collections.immutable) testImplementation(libs.test.junit) testImplementation(libs.coroutines.test) diff --git a/libraries/usersearch/impl/src/test/kotlin/io/element/android/libraries/usersearch/impl/MatrixUserListDataSourceTest.kt b/libraries/usersearch/impl/src/test/kotlin/io/element/android/libraries/usersearch/impl/MatrixUserListDataSourceTest.kt index 793a9f7f58..76f29aebe5 100644 --- a/libraries/usersearch/impl/src/test/kotlin/io/element/android/libraries/usersearch/impl/MatrixUserListDataSourceTest.kt +++ b/libraries/usersearch/impl/src/test/kotlin/io/element/android/libraries/usersearch/impl/MatrixUserListDataSourceTest.kt @@ -25,6 +25,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.FakeMatrixClient +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.test.runTest import org.junit.Test @@ -37,7 +38,7 @@ internal class MatrixUserListDataSourceTest { searchTerm = "test", result = Result.success( MatrixSearchUserResults( - results = listOf( + results = persistentListOf( aMatrixUserProfile(), aMatrixUserProfile(userId = A_USER_ID_2) ),