Use heroes to render room avatars

This commit is contained in:
Benoit Marty
2024-06-20 13:10:25 +02:00
parent 99c43a175d
commit 11e4ee34ed
11 changed files with 79 additions and 10 deletions

View File

@@ -25,9 +25,9 @@ import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.features.preferences.impl.R
import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.avatar.Avatar
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.list.ListItemContent
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
import io.element.android.libraries.designsystem.components.preferences.PreferencePage
@@ -114,7 +114,17 @@ fun EditDefaultNotificationSettingView(
Text(text = subtitle)
},
leadingContent = ListItemContent.Custom {
Avatar(avatarData = avatarData)
CompositeAvatar(
avatarData = avatarData,
heroes = summary.details.heroes.map { user ->
AvatarData(
id = user.userId.value,
name = user.displayName,
url = user.avatarUrl,
size = AvatarSize.CustomRoomNotificationSetting,
)
}
)
},
onClick = {
openRoomNotificationSettings(summary.details.roomId)

View File

@@ -49,6 +49,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.toPersistentList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -151,6 +152,7 @@ class RoomDetailsPresenter @Inject constructor(
isFavorite = isFavorite,
displayRolesAndPermissionsSettings = !room.isDm && isUserAdmin,
isPublic = isPublic,
heroes = roomInfo?.heroes.orEmpty().toPersistentList(),
eventSink = ::handleEvents,
)
}

View File

@@ -23,6 +23,8 @@ 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.RoomNotificationSettings
import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.collections.immutable.ImmutableList
data class RoomDetailsState(
val roomId: RoomId,
@@ -43,6 +45,7 @@ data class RoomDetailsState(
val isFavorite: Boolean,
val displayRolesAndPermissionsSettings: Boolean,
val isPublic: Boolean,
val heroes: ImmutableList<MatrixUser>,
val eventSink: (RoomDetailsEvent) -> Unit
)

View File

@@ -28,6 +28,8 @@ import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.RoomNotificationSettings
import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.collections.immutable.toPersistentList
open class RoomDetailsStateProvider : PreviewParameterProvider<RoomDetailsState> {
override val values: Sequence<RoomDetailsState>
@@ -99,6 +101,7 @@ fun aRoomDetailsState(
isFavorite: Boolean = false,
displayAdminSettings: Boolean = false,
isPublic: Boolean = true,
heroes: List<MatrixUser> = emptyList(),
eventSink: (RoomDetailsEvent) -> Unit = {},
) = RoomDetailsState(
roomId = roomId,
@@ -119,6 +122,7 @@ fun aRoomDetailsState(
isFavorite = isFavorite,
displayRolesAndPermissionsSettings = displayAdminSettings,
isPublic = isPublic,
heroes = heroes.toPersistentList(),
eventSink = eventSink
)

View File

@@ -54,9 +54,9 @@ 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
import io.element.android.libraries.designsystem.components.ClickableLinkText
import io.element.android.libraries.designsystem.components.avatar.Avatar
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.button.BackButton
import io.element.android.libraries.designsystem.components.button.MainActionButton
import io.element.android.libraries.designsystem.components.list.ListItemContent
@@ -81,6 +81,7 @@ 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.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.getBestName
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.testtags.TestTags
import io.element.android.libraries.testtags.testTag
import io.element.android.libraries.ui.strings.CommonStrings
@@ -127,6 +128,7 @@ fun RoomDetailsView(
roomAlias = state.roomAlias,
isEncrypted = state.isEncrypted,
isPublic = state.isPublic,
heroes = state.heroes,
openAvatarPreview = { avatarUrl ->
openAvatarPreview(state.roomName, avatarUrl)
},
@@ -324,6 +326,7 @@ private fun RoomHeaderSection(
roomAlias: RoomAlias?,
isEncrypted: Boolean,
isPublic: Boolean,
heroes: List<MatrixUser> = emptyList(),
openAvatarPreview: (url: String) -> Unit,
) {
Column(
@@ -332,8 +335,16 @@ private fun RoomHeaderSection(
.padding(horizontal = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Avatar(
CompositeAvatar(
avatarData = AvatarData(roomId.value, roomName, avatarUrl, AvatarSize.RoomHeader),
heroes = heroes.map { user ->
AvatarData(
id = user.userId.value,
name = user.displayName,
url = user.avatarUrl,
size = AvatarSize.RoomHeader
)
},
modifier = Modifier
.size(70.dp)
.clickable(enabled = avatarUrl != null) { openAvatarPreview(avatarUrl!!) }

View File

@@ -27,6 +27,8 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.ui.model.toInviteSender
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import javax.inject.Inject
class RoomListRoomSummaryFactory @Inject constructor(
@@ -54,6 +56,7 @@ class RoomListRoomSummaryFactory @Inject constructor(
inviteSender = null,
isDm = false,
canonicalAlias = null,
heroes = persistentListOf(),
)
}
}
@@ -90,7 +93,15 @@ class RoomListRoomSummaryFactory @Inject constructor(
RoomSummaryDisplayType.INVITE
} else {
RoomSummaryDisplayType.ROOM
}
},
heroes = roomSummary.details.heroes.map {
AvatarData(
id = it.userId.value,
name = it.displayName,
url = it.avatarUrl,
size = AvatarSize.RoomListItem,
)
}.toImmutableList(),
)
}
}

View File

@@ -22,6 +22,7 @@ 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.RoomNotificationMode
import io.element.android.libraries.matrix.ui.model.InviteSender
import kotlinx.collections.immutable.ImmutableList
@Immutable
data class RoomListRoomSummary(
@@ -43,6 +44,7 @@ data class RoomListRoomSummary(
val isDm: Boolean,
val isFavorite: Boolean,
val inviteSender: InviteSender?,
val heroes: ImmutableList<AvatarData>,
) {
val isHighlighted = userDefinedNotificationMode != RoomNotificationMode.MUTE &&
(numberOfUnreadNotifications > 0 || numberOfUnreadMentions > 0) ||

View File

@@ -24,6 +24,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.ui.model.InviteSender
import kotlinx.collections.immutable.toImmutableList
open class RoomListRoomSummaryProvider : PreviewParameterProvider<RoomListRoomSummary> {
override val values: Sequence<RoomListRoomSummary>
@@ -142,6 +143,7 @@ internal fun aRoomListRoomSummary(
inviteSender: InviteSender? = null,
displayType: RoomSummaryDisplayType = RoomSummaryDisplayType.ROOM,
canonicalAlias: RoomAlias? = null,
heroes: List<AvatarData> = emptyList(),
) = RoomListRoomSummary(
id = id,
roomId = RoomId(id),
@@ -161,4 +163,5 @@ internal fun aRoomListRoomSummary(
inviteSender = inviteSender,
displayType = displayType,
canonicalAlias = canonicalAlias,
heroes = heroes.toImmutableList(),
)

View File

@@ -53,7 +53,7 @@ fun CompositeAvatar(
}
when (numberOfHeroes) {
0 -> {
// Cannot happen
error("Unsupported number of heroes: 0")
}
1 -> {
Avatar(heroes[0], modifier, contentDescription)

View File

@@ -36,9 +36,9 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.libraries.designsystem.components.avatar.Avatar
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.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Icon
@@ -60,7 +60,22 @@ fun SelectedRoom(
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Avatar(AvatarData(roomSummary.roomId.value, roomSummary.name, roomSummary.avatarUrl, AvatarSize.SelectedRoom))
CompositeAvatar(
avatarData = AvatarData(
roomSummary.roomId.value,
roomSummary.name,
roomSummary.avatarUrl,
AvatarSize.SelectedRoom,
),
heroes = roomSummary.heroes.map {
AvatarData(
id = it.userId.value,
name = it.displayName,
url = it.avatarUrl,
size = AvatarSize.SelectedRoom
)
}
)
Text(
// If name is null, we do not have space to render "No room name", so just use `#` here.
text = roomSummary.name ?: "#",

View File

@@ -41,9 +41,9 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.components.avatar.Avatar
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.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@@ -221,13 +221,21 @@ private fun RoomSummaryView(
.heightIn(56.dp),
verticalAlignment = Alignment.CenterVertically
) {
Avatar(
CompositeAvatar(
avatarData = AvatarData(
id = summary.roomId.value,
name = summary.name,
url = summary.avatarUrl,
size = AvatarSize.RoomSelectRoomListItem,
),
heroes = summary.heroes.map {
AvatarData(
it.userId.value,
it.displayName,
it.avatarUrl,
AvatarSize.RoomSelectRoomListItem,
)
}
)
Column(
modifier = Modifier