Room badge: let the presenter compute the list of badges.

This commit is contained in:
Benoit Marty 2024-10-22 11:15:46 +02:00
parent 200ae60a8b
commit ebb79bb729
5 changed files with 121 additions and 37 deletions

View file

@ -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.libraries.matrix.ui.room.isOwnUserAdmin
import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analyticsproviders.api.trackers.captureInteraction import io.element.android.services.analyticsproviders.api.trackers.captureInteraction
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@ -112,6 +113,21 @@ class RoomDetailsPresenter @Inject constructor(
val roomNotificationSettingsState by room.roomNotificationSettingsStateFlow.collectAsState() 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) { fun handleEvents(event: RoomDetailsEvent) {
when (event) { when (event) {
RoomDetailsEvent.LeaveRoom -> RoomDetailsEvent.LeaveRoom ->
@ -151,6 +167,7 @@ class RoomDetailsPresenter @Inject constructor(
isFavorite = isFavorite, isFavorite = isFavorite,
displayRolesAndPermissionsSettings = !room.isDm && isUserAdmin, displayRolesAndPermissionsSettings = !room.isDm && isUserAdmin,
isPublic = isPublic, isPublic = isPublic,
roomBadges = roomBadges,
heroes = roomInfo?.heroes.orEmpty().toPersistentList(), heroes = roomInfo?.heroes.orEmpty().toPersistentList(),
canShowPinnedMessages = canShowPinnedMessages, canShowPinnedMessages = canShowPinnedMessages,
pinnedMessagesCount = pinnedMessagesCount, pinnedMessagesCount = pinnedMessagesCount,

View file

@ -36,6 +36,7 @@ data class RoomDetailsState(
val isFavorite: Boolean, val isFavorite: Boolean,
val displayRolesAndPermissionsSettings: Boolean, val displayRolesAndPermissionsSettings: Boolean,
val isPublic: Boolean, val isPublic: Boolean,
val roomBadges: ImmutableList<RoomBadge>,
val heroes: ImmutableList<MatrixUser>, val heroes: ImmutableList<MatrixUser>,
val canShowPinnedMessages: Boolean, val canShowPinnedMessages: Boolean,
val pinnedMessagesCount: Int?, val pinnedMessagesCount: Int?,
@ -57,3 +58,9 @@ sealed interface RoomTopicState {
data object CanAddTopic : RoomTopicState data object CanAddTopic : RoomTopicState
data class ExistingTopic(val topic: String) : RoomTopicState data class ExistingTopic(val topic: String) : RoomTopicState
} }
enum class RoomBadge {
ENCRYPTED,
NOT_ENCRYPTED,
PUBLIC;
}

View file

@ -96,6 +96,18 @@ fun aRoomDetailsState(
isFavorite: Boolean = false, isFavorite: Boolean = false,
displayAdminSettings: Boolean = false, displayAdminSettings: Boolean = false,
isPublic: Boolean = true, isPublic: Boolean = true,
roomBadges: List<RoomBadge> = buildList {
if (isEncrypted || isPublic) {
if (isEncrypted) {
add(RoomBadge.ENCRYPTED)
} else {
add(RoomBadge.NOT_ENCRYPTED)
}
}
if (isPublic) {
add(RoomBadge.PUBLIC)
}
},
heroes: List<MatrixUser> = emptyList(), heroes: List<MatrixUser> = emptyList(),
canShowPinnedMessages: Boolean = true, canShowPinnedMessages: Boolean = true,
pinnedMessagesCount: Int? = null, pinnedMessagesCount: Int? = null,
@ -119,6 +131,7 @@ fun aRoomDetailsState(
isFavorite = isFavorite, isFavorite = isFavorite,
displayRolesAndPermissionsSettings = displayAdminSettings, displayRolesAndPermissionsSettings = displayAdminSettings,
isPublic = isPublic, isPublic = isPublic,
roomBadges = roomBadges.toPersistentList(),
heroes = heroes.toPersistentList(), heroes = heroes.toPersistentList(),
canShowPinnedMessages = canShowPinnedMessages, canShowPinnedMessages = canShowPinnedMessages,
pinnedMessagesCount = pinnedMessagesCount, pinnedMessagesCount = pinnedMessagesCount,

View file

@ -147,8 +147,7 @@ fun RoomDetailsView(
} }
} }
BadgeList( BadgeList(
isEncrypted = state.isEncrypted, roomBadge = state.roomBadges,
isPublic = state.isPublic,
modifier = Modifier.align(Alignment.CenterHorizontally), modifier = Modifier.align(Alignment.CenterHorizontally),
) )
Spacer(Modifier.height(32.dp)) Spacer(Modifier.height(32.dp))
@ -403,42 +402,42 @@ private fun ColumnScope.TitleAndSubtitle(
@Composable @Composable
private fun BadgeList( private fun BadgeList(
isEncrypted: Boolean, roomBadge: ImmutableList<RoomBadge>,
isPublic: Boolean,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
if (isEncrypted || isPublic) { if (roomBadge.isEmpty()) return
MatrixBadgeRowMolecule( MatrixBadgeRowMolecule(
modifier = modifier, modifier = modifier,
data = buildList { data = roomBadge.map {
if (isEncrypted) { it.toMatrixBadgeData()
add( }.toImmutableList(),
MatrixBadgeAtom.MatrixBadgeData( )
text = stringResource(R.string.screen_room_details_badge_encrypted), }
icon = CompoundIcons.LockSolid(),
type = MatrixBadgeAtom.Type.Positive, @Composable
) private fun RoomBadge.toMatrixBadgeData(): MatrixBadgeAtom.MatrixBadgeData {
) return when (this) {
} else { RoomBadge.ENCRYPTED -> {
add( MatrixBadgeAtom.MatrixBadgeData(
MatrixBadgeAtom.MatrixBadgeData( text = stringResource(R.string.screen_room_details_badge_encrypted),
text = stringResource(R.string.screen_room_details_badge_not_encrypted), icon = CompoundIcons.LockSolid(),
icon = CompoundIcons.LockOff(), type = MatrixBadgeAtom.Type.Positive,
type = MatrixBadgeAtom.Type.Neutral, )
) }
) RoomBadge.NOT_ENCRYPTED -> {
} MatrixBadgeAtom.MatrixBadgeData(
if (isPublic) { text = stringResource(R.string.screen_room_details_badge_not_encrypted),
add( icon = CompoundIcons.LockOff(),
MatrixBadgeAtom.MatrixBadgeData( type = MatrixBadgeAtom.Type.Neutral,
text = stringResource(R.string.screen_room_details_badge_public), )
icon = CompoundIcons.Public(), }
type = MatrixBadgeAtom.Type.Neutral, RoomBadge.PUBLIC -> {
) MatrixBadgeAtom.MatrixBadgeData(
) text = stringResource(R.string.screen_room_details_badge_public),
} icon = CompoundIcons.Public(),
}.toImmutableList(), type = MatrixBadgeAtom.Type.Neutral,
) )
}
} }
} }

View file

@ -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.LeaveRoomEvent
import io.element.android.features.leaveroom.api.LeaveRoomState import io.element.android.features.leaveroom.api.LeaveRoomState
import io.element.android.features.leaveroom.api.aLeaveRoomState 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.RoomDetailsEvent
import io.element.android.features.roomdetails.impl.RoomDetailsPresenter import io.element.android.features.roomdetails.impl.RoomDetailsPresenter
import io.element.android.features.roomdetails.impl.RoomDetailsState import io.element.android.features.roomdetails.impl.RoomDetailsState
@ -134,7 +135,8 @@ class RoomDetailsPresenterTest {
assertThat(initialState.isEncrypted).isEqualTo(room.isEncrypted) assertThat(initialState.isEncrypted).isEqualTo(room.isEncrypted)
assertThat(initialState.canShowPinnedMessages).isTrue() assertThat(initialState.canShowPinnedMessages).isTrue()
assertThat(initialState.pinnedMessagesCount).isNull() 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 { fun `present - initial state is updated with roomInfo if it exists`() = runTest {
val roomInfo = aRoomInfo( val roomInfo = aRoomInfo(
name = A_ROOM_NAME, name = A_ROOM_NAME,
isPublic = true,
topic = A_ROOM_TOPIC, topic = A_ROOM_TOPIC,
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
pinnedEventIds = listOf(AN_EVENT_ID), pinnedEventIds = listOf(AN_EVENT_ID),
@ -161,10 +164,55 @@ class RoomDetailsPresenterTest {
assertThat(updatedState.roomAvatarUrl).isEqualTo(roomInfo.avatarUrl) assertThat(updatedState.roomAvatarUrl).isEqualTo(roomInfo.avatarUrl)
assertThat(updatedState.roomTopic).isEqualTo(RoomTopicState.ExistingTopic(roomInfo.topic!!)) assertThat(updatedState.roomTopic).isEqualTo(RoomTopicState.ExistingTopic(roomInfo.topic!!))
assertThat(updatedState.pinnedMessagesCount).isEqualTo(roomInfo.pinnedEventIds.size) assertThat(updatedState.pinnedMessagesCount).isEqualTo(roomInfo.pinnedEventIds.size)
assertThat(updatedState.roomBadges).isEqualTo(listOf(RoomBadge.ENCRYPTED, RoomBadge.PUBLIC))
cancelAndIgnoreRemainingEvents() 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 @Test
fun `present - initial state with no room name`() = runTest { fun `present - initial state with no room name`() = runTest {
val room = aMatrixRoom( val room = aMatrixRoom(