diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt index eccc8dd9d2..2594fd5509 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt @@ -43,6 +43,7 @@ import io.element.android.libraries.matrix.ui.room.getDirectRoomMember import io.element.android.libraries.matrix.ui.room.isOwnUserAdmin import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analyticsproviders.api.trackers.captureInteraction +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn @@ -112,6 +113,21 @@ class RoomDetailsPresenter @Inject constructor( val roomNotificationSettingsState by room.roomNotificationSettingsStateFlow.collectAsState() + val roomBadges by produceState(persistentListOf(), isPublic) { + value = buildList { + if (room.isEncrypted || isPublic) { + if (room.isEncrypted) { + add(RoomBadge.ENCRYPTED) + } else { + add(RoomBadge.NOT_ENCRYPTED) + } + } + if (isPublic) { + add(RoomBadge.PUBLIC) + } + }.toPersistentList() + } + fun handleEvents(event: RoomDetailsEvent) { when (event) { RoomDetailsEvent.LeaveRoom -> @@ -151,6 +167,7 @@ class RoomDetailsPresenter @Inject constructor( isFavorite = isFavorite, displayRolesAndPermissionsSettings = !room.isDm && isUserAdmin, isPublic = isPublic, + roomBadges = roomBadges, heroes = roomInfo?.heroes.orEmpty().toPersistentList(), canShowPinnedMessages = canShowPinnedMessages, pinnedMessagesCount = pinnedMessagesCount, diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt index 1abaa59d93..3116f70015 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt @@ -36,6 +36,7 @@ data class RoomDetailsState( val isFavorite: Boolean, val displayRolesAndPermissionsSettings: Boolean, val isPublic: Boolean, + val roomBadges: ImmutableList, val heroes: ImmutableList, val canShowPinnedMessages: Boolean, val pinnedMessagesCount: Int?, @@ -57,3 +58,9 @@ sealed interface RoomTopicState { data object CanAddTopic : RoomTopicState data class ExistingTopic(val topic: String) : RoomTopicState } + +enum class RoomBadge { + ENCRYPTED, + NOT_ENCRYPTED, + PUBLIC; +} diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt index d9b0c22c65..5462bc65a7 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt @@ -96,6 +96,18 @@ fun aRoomDetailsState( isFavorite: Boolean = false, displayAdminSettings: Boolean = false, isPublic: Boolean = true, + roomBadges: List = buildList { + if (isEncrypted || isPublic) { + if (isEncrypted) { + add(RoomBadge.ENCRYPTED) + } else { + add(RoomBadge.NOT_ENCRYPTED) + } + } + if (isPublic) { + add(RoomBadge.PUBLIC) + } + }, heroes: List = emptyList(), canShowPinnedMessages: Boolean = true, pinnedMessagesCount: Int? = null, @@ -119,6 +131,7 @@ fun aRoomDetailsState( isFavorite = isFavorite, displayRolesAndPermissionsSettings = displayAdminSettings, isPublic = isPublic, + roomBadges = roomBadges.toPersistentList(), heroes = heroes.toPersistentList(), canShowPinnedMessages = canShowPinnedMessages, pinnedMessagesCount = pinnedMessagesCount, diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt index 8291b3e1c8..b37b23a898 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt @@ -147,8 +147,7 @@ fun RoomDetailsView( } } BadgeList( - isEncrypted = state.isEncrypted, - isPublic = state.isPublic, + roomBadge = state.roomBadges, modifier = Modifier.align(Alignment.CenterHorizontally), ) Spacer(Modifier.height(32.dp)) @@ -403,42 +402,42 @@ private fun ColumnScope.TitleAndSubtitle( @Composable private fun BadgeList( - isEncrypted: Boolean, - isPublic: Boolean, + roomBadge: ImmutableList, modifier: Modifier = Modifier, ) { - if (isEncrypted || isPublic) { - MatrixBadgeRowMolecule( - modifier = modifier, - data = buildList { - if (isEncrypted) { - add( - MatrixBadgeAtom.MatrixBadgeData( - text = stringResource(R.string.screen_room_details_badge_encrypted), - icon = CompoundIcons.LockSolid(), - type = MatrixBadgeAtom.Type.Positive, - ) - ) - } else { - add( - MatrixBadgeAtom.MatrixBadgeData( - text = stringResource(R.string.screen_room_details_badge_not_encrypted), - icon = CompoundIcons.LockOff(), - type = MatrixBadgeAtom.Type.Neutral, - ) - ) - } - if (isPublic) { - add( - MatrixBadgeAtom.MatrixBadgeData( - text = stringResource(R.string.screen_room_details_badge_public), - icon = CompoundIcons.Public(), - type = MatrixBadgeAtom.Type.Neutral, - ) - ) - } - }.toImmutableList(), - ) + if (roomBadge.isEmpty()) return + MatrixBadgeRowMolecule( + modifier = modifier, + data = roomBadge.map { + it.toMatrixBadgeData() + }.toImmutableList(), + ) +} + +@Composable +private fun RoomBadge.toMatrixBadgeData(): MatrixBadgeAtom.MatrixBadgeData { + return when (this) { + RoomBadge.ENCRYPTED -> { + MatrixBadgeAtom.MatrixBadgeData( + text = stringResource(R.string.screen_room_details_badge_encrypted), + icon = CompoundIcons.LockSolid(), + type = MatrixBadgeAtom.Type.Positive, + ) + } + RoomBadge.NOT_ENCRYPTED -> { + MatrixBadgeAtom.MatrixBadgeData( + text = stringResource(R.string.screen_room_details_badge_not_encrypted), + icon = CompoundIcons.LockOff(), + type = MatrixBadgeAtom.Type.Neutral, + ) + } + RoomBadge.PUBLIC -> { + MatrixBadgeAtom.MatrixBadgeData( + text = stringResource(R.string.screen_room_details_badge_public), + icon = CompoundIcons.Public(), + type = MatrixBadgeAtom.Type.Neutral, + ) + } } } diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTest.kt index 9a893b671e..e678a31641 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTest.kt @@ -17,6 +17,7 @@ import im.vector.app.features.analytics.plan.Interaction import io.element.android.features.leaveroom.api.LeaveRoomEvent import io.element.android.features.leaveroom.api.LeaveRoomState import io.element.android.features.leaveroom.api.aLeaveRoomState +import io.element.android.features.roomdetails.impl.RoomBadge import io.element.android.features.roomdetails.impl.RoomDetailsEvent import io.element.android.features.roomdetails.impl.RoomDetailsPresenter import io.element.android.features.roomdetails.impl.RoomDetailsState @@ -134,7 +135,8 @@ class RoomDetailsPresenterTest { assertThat(initialState.isEncrypted).isEqualTo(room.isEncrypted) assertThat(initialState.canShowPinnedMessages).isTrue() assertThat(initialState.pinnedMessagesCount).isNull() - cancelAndIgnoreRemainingEvents() + assertThat(initialState.roomBadges).isEmpty() + assertThat(awaitItem().roomBadges).isEqualTo(listOf(RoomBadge.ENCRYPTED)) } } @@ -142,6 +144,7 @@ class RoomDetailsPresenterTest { fun `present - initial state is updated with roomInfo if it exists`() = runTest { val roomInfo = aRoomInfo( name = A_ROOM_NAME, + isPublic = true, topic = A_ROOM_TOPIC, avatarUrl = AN_AVATAR_URL, pinnedEventIds = listOf(AN_EVENT_ID), @@ -161,10 +164,55 @@ class RoomDetailsPresenterTest { assertThat(updatedState.roomAvatarUrl).isEqualTo(roomInfo.avatarUrl) assertThat(updatedState.roomTopic).isEqualTo(RoomTopicState.ExistingTopic(roomInfo.topic!!)) assertThat(updatedState.pinnedMessagesCount).isEqualTo(roomInfo.pinnedEventIds.size) + assertThat(updatedState.roomBadges).isEqualTo(listOf(RoomBadge.ENCRYPTED, RoomBadge.PUBLIC)) cancelAndIgnoreRemainingEvents() } } + @Test + fun `present - initial state not public not encrypted should have no badges`() = runTest { + val roomInfo = aRoomInfo( + name = A_ROOM_NAME, + isPublic = false, + ) + val room = aMatrixRoom( + isEncrypted = false, + canInviteResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canSendStateResult = { _, _ -> Result.success(true) }, + ).apply { + givenRoomInfo(roomInfo) + } + val presenter = createRoomDetailsPresenter(room) + presenter.test { + skipItems(1) + val updatedState = awaitItem() + assertThat(updatedState.roomBadges).isEmpty() + } + } + + @Test + fun `present - initial state public not encrypted should have not encrypted and public badges`() = runTest { + val roomInfo = aRoomInfo( + name = A_ROOM_NAME, + isPublic = true, + ) + val room = aMatrixRoom( + isEncrypted = false, + canInviteResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canSendStateResult = { _, _ -> Result.success(true) }, + ).apply { + givenRoomInfo(roomInfo) + } + val presenter = createRoomDetailsPresenter(room) + presenter.test { + skipItems(1) + val updatedState = awaitItem() + assertThat(updatedState.roomBadges).isEqualTo(listOf(RoomBadge.NOT_ENCRYPTED, RoomBadge.PUBLIC)) + } + } + @Test fun `present - initial state with no room name`() = runTest { val room = aMatrixRoom(