change(room details) : update room details with new sections organisation

This commit is contained in:
ganfra 2025-01-17 13:05:25 +01:00
parent 0856a9ac62
commit 1aa0afd280
4 changed files with 85 additions and 67 deletions

View file

@ -33,6 +33,7 @@ import io.element.android.features.roomdetails.impl.members.RoomMemberListNode
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsNode import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsNode
import io.element.android.features.roomdetails.impl.notificationsettings.RoomNotificationSettingsNode import io.element.android.features.roomdetails.impl.notificationsettings.RoomNotificationSettingsNode
import io.element.android.features.roomdetails.impl.rolesandpermissions.RolesAndPermissionsFlowNode import io.element.android.features.roomdetails.impl.rolesandpermissions.RolesAndPermissionsFlowNode
import io.element.android.features.roomdetails.impl.securityandprivacy.SecurityAndPrivacyNode
import io.element.android.features.userprofile.shared.UserProfileNodeHelper import io.element.android.features.userprofile.shared.UserProfileNodeHelper
import io.element.android.libraries.architecture.BackstackWithOverlayBox import io.element.android.libraries.architecture.BackstackWithOverlayBox
import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.BaseFlowNode
@ -114,6 +115,9 @@ class RoomDetailsFlowNode @AssistedInject constructor(
@Parcelize @Parcelize
data object KnockRequestsList : NavTarget data object KnockRequestsList : NavTarget
@Parcelize
data object SecurityAndPrivacy : NavTarget
} }
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
@ -160,6 +164,10 @@ class RoomDetailsFlowNode @AssistedInject constructor(
backstack.push(NavTarget.KnockRequestsList) backstack.push(NavTarget.KnockRequestsList)
} }
override fun openSecurityAndPrivacy() {
backstack.push(NavTarget.SecurityAndPrivacy)
}
override fun onJoinCall() { override fun onJoinCall() {
val inputs = CallType.RoomCall( val inputs = CallType.RoomCall(
sessionId = room.sessionId, sessionId = room.sessionId,
@ -290,6 +298,9 @@ class RoomDetailsFlowNode @AssistedInject constructor(
NavTarget.KnockRequestsList -> { NavTarget.KnockRequestsList -> {
knockRequestsListEntryPoint.createNode(this, buildContext) knockRequestsListEntryPoint.createNode(this, buildContext)
} }
NavTarget.SecurityAndPrivacy -> {
createNode<SecurityAndPrivacyNode>(buildContext)
}
} }
} }

View file

@ -49,6 +49,7 @@ class RoomDetailsNode @AssistedInject constructor(
fun openAdminSettings() fun openAdminSettings()
fun openPinnedMessagesList() fun openPinnedMessagesList()
fun openKnockRequestsList() fun openKnockRequestsList()
fun openSecurityAndPrivacy()
fun onJoinCall() fun onJoinCall()
} }
@ -121,6 +122,10 @@ class RoomDetailsNode @AssistedInject constructor(
callbacks.forEach { it.openKnockRequestsList() } callbacks.forEach { it.openKnockRequestsList() }
} }
private fun openSecurityAndPrivacy() {
callbacks.forEach { it.openSecurityAndPrivacy() }
}
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
val context = LocalContext.current val context = LocalContext.current
@ -153,6 +158,7 @@ class RoomDetailsNode @AssistedInject constructor(
onJoinCallClick = ::onJoinCall, onJoinCallClick = ::onJoinCall,
onPinnedMessagesClick = ::openPinnedMessages, onPinnedMessagesClick = ::openPinnedMessages,
onKnockRequestsClick = ::openKnockRequestsLists, onKnockRequestsClick = ::openKnockRequestsLists,
onSecurityAndPrivacyClick = ::openSecurityAndPrivacy
) )
} }
} }

View file

@ -12,7 +12,6 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.consumeWindowInsets
@ -73,7 +72,6 @@ import io.element.android.libraries.designsystem.theme.components.ListItemStyle
import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.designsystem.utils.CommonDrawables
import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMember
@ -106,6 +104,7 @@ fun RoomDetailsView(
onJoinCallClick: () -> Unit, onJoinCallClick: () -> Unit,
onPinnedMessagesClick: () -> Unit, onPinnedMessagesClick: () -> Unit,
onKnockRequestsClick: () -> Unit, onKnockRequestsClick: () -> Unit,
onSecurityAndPrivacyClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Scaffold( Scaffold(
@ -185,24 +184,12 @@ fun RoomDetailsView(
} }
) )
if (state.canShowPinnedMessages) { SecurityAndPrivacyItem(
PinnedMessagesItem( onClick = onSecurityAndPrivacyClick
pinnedMessagesCount = state.pinnedMessagesCount, )
onPinnedMessagesClick = onPinnedMessagesClick
)
}
if (state.displayRolesAndPermissionsSettings) {
ListItem(
headlineContent = { Text(stringResource(R.string.screen_room_details_roles_and_permissions)) },
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Admin())),
onClick = openAdminSettings,
)
}
} }
val displayMemberListItem = state.roomType is RoomDetailsType.Room if (state.roomType is RoomDetailsType.Room) {
if (displayMemberListItem) {
PreferenceCategory { PreferenceCategory {
MembersItem( MembersItem(
memberCount = state.memberCount, memberCount = state.memberCount,
@ -214,19 +201,31 @@ fun RoomDetailsView(
onKnockRequestsClick = onKnockRequestsClick onKnockRequestsClick = onKnockRequestsClick
) )
} }
if (state.displayRolesAndPermissionsSettings) {
ListItem(
headlineContent = { Text(stringResource(R.string.screen_room_details_roles_and_permissions)) },
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Admin())),
onClick = openAdminSettings,
)
}
} }
} }
PollsSection( PreferenceCategory {
openPollHistory = openPollHistory if (state.canShowPinnedMessages) {
) PinnedMessagesItem(
if (state.canShowMediaGallery) { pinnedMessagesCount = state.pinnedMessagesCount,
MediaGallerySection( onPinnedMessagesClick = onPinnedMessagesClick
onClick = openMediaGallery )
}
PollsItem(
openPollHistory = openPollHistory
) )
} if (state.canShowMediaGallery) {
if (state.isEncrypted) { MediaGalleryItem(
SecuritySection() onClick = openMediaGallery
)
}
} }
if (state.roomType is RoomDetailsType.Dm && state.roomMemberDetailsState != null) { if (state.roomType is RoomDetailsType.Dm && state.roomMemberDetailsState != null) {
@ -408,24 +407,26 @@ private fun DmHeaderSection(
} }
@Composable @Composable
private fun ColumnScope.TitleAndSubtitle( private fun TitleAndSubtitle(
title: String, title: String,
subtitle: String?, subtitle: String?,
) { ) {
Spacer(modifier = Modifier.height(24.dp)) Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text( Spacer(modifier = Modifier.height(24.dp))
text = title,
style = ElementTheme.typography.fontHeadingLgBold,
textAlign = TextAlign.Center,
)
if (subtitle != null) {
Spacer(modifier = Modifier.height(6.dp))
Text( Text(
text = subtitle, text = title,
style = ElementTheme.typography.fontBodyLgRegular, style = ElementTheme.typography.fontHeadingLgBold,
color = MaterialTheme.colorScheme.secondary,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
) )
if (subtitle != null) {
Spacer(modifier = Modifier.height(6.dp))
Text(
text = subtitle,
style = ElementTheme.typography.fontBodyLgRegular,
color = MaterialTheme.colorScheme.secondary,
textAlign = TextAlign.Center,
)
}
} }
} }
@ -518,6 +519,19 @@ private fun NotificationItem(
) )
} }
@Composable
private fun SecurityAndPrivacyItem(
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
ListItem(
headlineContent = { Text(stringResource(R.string.screen_room_details_security_and_privacy_title)) },
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Lock())),
onClick = onClick,
modifier = modifier,
)
}
@Composable @Composable
private fun FavoriteItem( private fun FavoriteItem(
isFavorite: Boolean, isFavorite: Boolean,
@ -569,40 +583,25 @@ private fun PinnedMessagesItem(
} }
@Composable @Composable
private fun PollsSection( private fun PollsItem(
openPollHistory: () -> Unit, openPollHistory: () -> Unit,
) { ) {
PreferenceCategory { ListItem(
ListItem( headlineContent = { Text(stringResource(R.string.screen_polls_history_title)) },
headlineContent = { Text(stringResource(R.string.screen_polls_history_title)) }, leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Polls())),
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Polls())), onClick = openPollHistory,
onClick = openPollHistory, )
)
}
} }
@Composable @Composable
private fun MediaGallerySection( private fun MediaGalleryItem(
onClick: () -> Unit, onClick: () -> Unit,
) { ) {
PreferenceCategory { ListItem(
ListItem( headlineContent = { Text(stringResource(R.string.screen_room_details_media_gallery_title)) },
headlineContent = { Text(stringResource(R.string.screen_room_details_media_gallery_title)) }, leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Image())),
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Image())), onClick = onClick,
onClick = onClick, )
)
}
}
@Composable
private fun SecuritySection() {
PreferenceCategory(title = stringResource(R.string.screen_room_details_security_title)) {
ListItem(
headlineContent = { Text(stringResource(R.string.screen_room_details_encryption_enabled_title)) },
supportingContent = { Text(stringResource(R.string.screen_room_details_encryption_enabled_subtitle)) },
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_encryption_enabled)),
)
}
} }
@Composable @Composable
@ -654,5 +653,6 @@ private fun ContentToPreview(state: RoomDetailsState) {
onJoinCallClick = {}, onJoinCallClick = {},
onPinnedMessagesClick = {}, onPinnedMessagesClick = {},
onKnockRequestsClick = {}, onKnockRequestsClick = {},
onSecurityAndPrivacyClick = {},
) )
} }

View file

@ -17,6 +17,7 @@ import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.isDm
import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.matrix.api.room.roomMembers
@Composable @Composable
@ -44,7 +45,7 @@ fun MatrixRoom.getDirectRoomMember(roomMembersState: MatrixRoomMembersState): St
derivedStateOf { derivedStateOf {
roomMembers roomMembers
?.filter { it.membership.isActive() } ?.filter { it.membership.isActive() }
?.takeIf { it.size == 2 && isDirect } ?.takeIf { isDm }
?.find { it.userId != sessionId } ?.find { it.userId != sessionId }
} }
} }