Browse Source

Use DmAvatars in header of DM details.

pull/3069/head
Benoit Marty 3 months ago
parent
commit
da1f8cd465
  1. 16
      features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt
  2. 5
      features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt
  3. 6
      features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt
  4. 58
      features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt
  5. 8
      features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTest.kt
  6. 7
      features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsViewTest.kt
  7. 3
      libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/DmAvatars.kt
  8. 11
      libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomMembers.kt

16
features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt

@ -45,6 +45,7 @@ import io.element.android.libraries.matrix.api.room.powerlevels.canInvite @@ -45,6 +45,7 @@ import io.element.android.libraries.matrix.api.room.powerlevels.canInvite
import io.element.android.libraries.matrix.api.room.powerlevels.canSendState
import io.element.android.libraries.matrix.api.room.roomNotificationSettings
import io.element.android.libraries.matrix.ui.room.canCall
import io.element.android.libraries.matrix.ui.room.getCurrentRoomMember
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
@ -98,8 +99,9 @@ class RoomDetailsPresenter @Inject constructor( @@ -98,8 +99,9 @@ class RoomDetailsPresenter @Inject constructor(
val canEditTopic by getCanSendState(membersState, StateEventType.ROOM_TOPIC)
val canJoinCall by room.canCall(updateKey = syncUpdateTimestamp)
val dmMember by room.getDirectRoomMember(membersState)
val currentMember by room.getCurrentRoomMember(membersState)
val roomMemberDetailsPresenter = roomMemberDetailsPresenter(dmMember)
val roomType by getRoomType(dmMember)
val roomType by getRoomType(dmMember, currentMember)
val topicState = remember(canEditTopic, roomTopic, roomType) {
val topic = roomTopic
@ -165,10 +167,16 @@ class RoomDetailsPresenter @Inject constructor( @@ -165,10 +167,16 @@ class RoomDetailsPresenter @Inject constructor(
}
@Composable
private fun getRoomType(dmMember: RoomMember?): State<RoomDetailsType> = remember(dmMember) {
private fun getRoomType(
dmMember: RoomMember?,
currentMember: RoomMember?,
): State<RoomDetailsType> = remember(dmMember, currentMember) {
derivedStateOf {
if (dmMember != null) {
RoomDetailsType.Dm(dmMember)
if (dmMember != null && currentMember != null) {
RoomDetailsType.Dm(
me = currentMember,
roomMember = dmMember,
)
} else {
RoomDetailsType.Room
}

5
features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt

@ -52,7 +52,10 @@ data class RoomDetailsState( @@ -52,7 +52,10 @@ data class RoomDetailsState(
@Immutable
sealed interface RoomDetailsType {
data object Room : RoomDetailsType
data class Dm(val roomMember: RoomMember) : RoomDetailsType
data class Dm(
val me: RoomMember,
val roomMember: RoomMember,
) : RoomDetailsType
}
@Immutable

6
features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt

@ -19,6 +19,7 @@ package io.element.android.features.roomdetails.impl @@ -19,6 +19,7 @@ package io.element.android.features.roomdetails.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.leaveroom.api.LeaveRoomState
import io.element.android.features.leaveroom.api.aLeaveRoomState
import io.element.android.features.roomdetails.impl.members.aRoomMember
import io.element.android.features.userprofile.shared.UserProfileState
import io.element.android.features.userprofile.shared.aUserProfileState
import io.element.android.libraries.matrix.api.core.RoomAlias
@ -141,6 +142,9 @@ fun aDmRoomDetailsState( @@ -141,6 +142,9 @@ fun aDmRoomDetailsState(
roomName: String = "Daniel",
) = aRoomDetailsState(
roomName = roomName,
roomType = RoomDetailsType.Dm(aDmRoomMember(isIgnored = isDmMemberIgnored)),
roomType = RoomDetailsType.Dm(
aRoomMember(),
aDmRoomMember(isIgnored = isDmMemberIgnored),
),
roomMemberDetailsState = aUserProfileState()
)

58
features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt

@ -40,6 +40,7 @@ import androidx.compose.runtime.remember @@ -40,6 +40,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewParameter
@ -48,7 +49,6 @@ import io.element.android.compound.theme.ElementTheme @@ -48,7 +49,6 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.leaveroom.api.LeaveRoomView
import io.element.android.features.roomdetails.impl.components.RoomBadge
import io.element.android.features.userprofile.shared.UserProfileHeaderSection
import io.element.android.features.userprofile.shared.blockuser.BlockUserDialogs
import io.element.android.features.userprofile.shared.blockuser.BlockUserSection
import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage
@ -56,6 +56,7 @@ import io.element.android.libraries.designsystem.components.ClickableLinkText @@ -56,6 +56,7 @@ import io.element.android.libraries.designsystem.components.ClickableLinkText
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.avatar.CompositeAvatar
import io.element.android.libraries.designsystem.components.avatar.DmAvatars
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.button.MainActionButton
import io.element.android.libraries.designsystem.components.list.ListItemContent
@ -78,6 +79,7 @@ import io.element.android.libraries.designsystem.theme.components.TopAppBar @@ -78,6 +79,7 @@ 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.RoomId
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.getBestName
import io.element.android.libraries.matrix.api.user.MatrixUser
@ -137,13 +139,12 @@ fun RoomDetailsView( @@ -137,13 +139,12 @@ fun RoomDetailsView(
)
}
is RoomDetailsType.Dm -> {
val member = state.roomType.roomMember
UserProfileHeaderSection(
avatarUrl = state.roomAvatarUrl ?: member.avatarUrl,
userId = member.userId,
userName = state.roomName,
openAvatarPreview = { avatarUrl ->
openAvatarPreview(member.getBestName(), avatarUrl)
DmHeaderSection(
me = state.roomType.me,
otherMember = state.roomType.roomMember,
roomName = state.roomName,
openAvatarPreview = { name, avatarUrl ->
openAvatarPreview(name, avatarUrl)
},
)
}
@ -359,6 +360,47 @@ private fun RoomHeaderSection( @@ -359,6 +360,47 @@ private fun RoomHeaderSection(
}
}
@Composable
private fun DmHeaderSection(
me: RoomMember,
otherMember: RoomMember,
roomName: String,
openAvatarPreview: (name: String, url: String) -> Unit,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
DmAvatars(
userAvatarData = me.getAvatarData(size = AvatarSize.DmCluster),
otherUserAvatarData = otherMember.getAvatarData(size = AvatarSize.DmCluster),
openAvatarPreview = { url -> openAvatarPreview(me.getBestName(), url) },
openOtherAvatarPreview = { url -> openAvatarPreview(roomName, url) },
)
Spacer(modifier = Modifier.height(24.dp))
Text(
modifier = Modifier.clipToBounds(),
text = roomName,
style = ElementTheme.typography.fontHeadingLgBold,
textAlign = TextAlign.Center,
)
Spacer(modifier = Modifier.height(6.dp))
Text(
text = otherMember.userId.value,
style = ElementTheme.typography.fontBodyLgRegular,
color = MaterialTheme.colorScheme.secondary,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
textAlign = TextAlign.Center,
)
Spacer(Modifier.height(40.dp))
}
}
@Composable
private fun BadgeList(
isEncrypted: Boolean,

8
features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTest.kt

@ -169,8 +169,12 @@ class RoomDetailsPresenterTest { @@ -169,8 +169,12 @@ class RoomDetailsPresenterTest {
val presenter = createRoomDetailsPresenter(room)
presenter.test {
val initialState = awaitItem()
assertThat(initialState.roomType).isEqualTo(RoomDetailsType.Dm(otherRoomMember))
assertThat(initialState.roomType).isEqualTo(
RoomDetailsType.Dm(
me = myRoomMember,
roomMember = otherRoomMember,
)
)
cancelAndIgnoreRemainingEvents()
}
}

7
features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsViewTest.kt

@ -23,6 +23,7 @@ import androidx.compose.ui.test.onNodeWithContentDescription @@ -23,6 +23,7 @@ import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.features.roomdetails.impl.members.aRoomMember
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.testtags.TestTags
import io.element.android.libraries.ui.strings.CommonStrings
@ -177,7 +178,11 @@ class RoomDetailsViewTest { @@ -177,7 +178,11 @@ class RoomDetailsViewTest {
fun `click on avatar test on DM`() {
val eventsRecorder = EventsRecorder<RoomDetailsEvent>(expectEvents = false)
val state = aRoomDetailsState(
roomType = RoomDetailsType.Dm(aDmRoomMember(avatarUrl = "an_avatar_url")),
roomType = RoomDetailsType.Dm(
aRoomMember(),
aDmRoomMember(avatarUrl = "an_avatar_url"),
),
roomName = "Daniel",
eventSink = eventsRecorder,
)
val callback = EnsureCalledOnceWithTwoParams("Daniel", "an_avatar_url")

3
libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/DmAvatars.kt

@ -34,6 +34,8 @@ import androidx.compose.ui.tooling.preview.Preview @@ -34,6 +34,8 @@ import androidx.compose.ui.tooling.preview.Preview
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
import io.element.android.libraries.designsystem.text.toPx
import io.element.android.libraries.testtags.TestTags
import io.element.android.libraries.testtags.testTag
/**
* https://www.figma.com/design/A2pAEvTEpJZBiOPUlcMnKi/Settings-%2B-Room-Details-(new)?node-id=1787-56333
@ -90,6 +92,7 @@ fun DmAvatars( @@ -90,6 +92,7 @@ fun DmAvatars(
.clickable(enabled = otherUserAvatarData.url != null) {
otherUserAvatarData.url?.let { openOtherAvatarPreview(it) }
}
.testTag(TestTags.memberDetailAvatar)
)
}
}

11
libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomMembers.kt

@ -63,3 +63,14 @@ fun MatrixRoom.getDirectRoomMember(roomMembersState: MatrixRoomMembersState): St @@ -63,3 +63,14 @@ fun MatrixRoom.getDirectRoomMember(roomMembersState: MatrixRoomMembersState): St
}
}
}
@Composable
fun MatrixRoom.getCurrentRoomMember(roomMembersState: MatrixRoomMembersState): State<RoomMember?> {
val roomMembers = roomMembersState.roomMembers()
return remember(roomMembersState) {
derivedStateOf {
roomMembers
?.find { it.userId == sessionId }
}
}
}

Loading…
Cancel
Save