From 290e4be82d4157a27ce14ca96cef9f40f29d3b4f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 23 Jun 2025 18:02:34 +0200 Subject: [PATCH] Extract ImageAvatar and InitialLetterAvatar to their own files. --- .../designsystem/components/avatar/Avatar.kt | 71 ------------------- .../components/avatar/ImageAvatar.kt | 66 +++++++++++++++++ .../components/avatar/InitialLetterAvatar.kt | 32 +++++++++ 3 files changed, 98 insertions(+), 71 deletions(-) create mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/ImageAvatar.kt create mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/InitialLetterAvatar.kt diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/Avatar.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/Avatar.kt index 4f691c9f0d..7358bd4ce3 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/Avatar.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/Avatar.kt @@ -9,28 +9,17 @@ package io.element.android.libraries.designsystem.components.avatar import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable -import androidx.compose.runtime.SideEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import coil3.compose.AsyncImagePainter -import coil3.compose.SubcomposeAsyncImage -import coil3.compose.SubcomposeAsyncImageContent -import io.element.android.libraries.designsystem.colors.AvatarColorsProvider import io.element.android.libraries.designsystem.preview.ElementThemedPreview import io.element.android.libraries.designsystem.preview.PreviewGroup import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.utils.CommonDrawables -import timber.log.Timber @Composable fun Avatar( @@ -95,66 +84,6 @@ private fun UserAvatar( } } -@Composable -internal fun ImageAvatar( - avatarData: AvatarData, - avatarType: AvatarType, - forcedAvatarSize: Dp?, - modifier: Modifier = Modifier, - contentDescription: String? = null, -) { - val size = forcedAvatarSize ?: avatarData.size.dp - SubcomposeAsyncImage( - model = avatarData, - contentDescription = contentDescription, - contentScale = ContentScale.Crop, - modifier = modifier - .size(size) - .clip(avatarShape(avatarType)) - ) { - val collectedState by painter.state.collectAsState() - when (val state = collectedState) { - is AsyncImagePainter.State.Success -> SubcomposeAsyncImageContent() - is AsyncImagePainter.State.Error -> { - SideEffect { - Timber.e(state.result.throwable, "Error loading avatar $state\n${state.result}") - } - InitialLetterAvatar( - avatarData = avatarData, - avatarType = avatarType, - forcedAvatarSize = forcedAvatarSize, - contentDescription = contentDescription, - ) - } - else -> InitialLetterAvatar( - avatarData = avatarData, - avatarType = avatarType, - forcedAvatarSize = forcedAvatarSize, - contentDescription = contentDescription, - ) - } - } -} - -@Composable -internal fun InitialLetterAvatar( - avatarData: AvatarData, - avatarType: AvatarType, - forcedAvatarSize: Dp?, - contentDescription: String?, - modifier: Modifier = Modifier, -) { - val avatarColors = AvatarColorsProvider.provide(avatarData.id) - TextAvatar( - text = avatarData.initialLetter, - size = forcedAvatarSize ?: avatarData.size.dp, - avatarType = avatarType, - colors = avatarColors, - contentDescription = contentDescription, - modifier = modifier - ) -} - @Preview(group = PreviewGroup.Avatars) @Composable internal fun AvatarPreview(@PreviewParameter(AvatarDataProvider::class) avatarData: AvatarData) = diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/ImageAvatar.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/ImageAvatar.kt new file mode 100644 index 0000000000..38f861b0e8 --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/ImageAvatar.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.designsystem.components.avatar + +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.Dp +import coil3.compose.AsyncImagePainter +import coil3.compose.SubcomposeAsyncImage +import coil3.compose.SubcomposeAsyncImageContent +import timber.log.Timber + +@Composable +internal fun ImageAvatar( + avatarData: AvatarData, + avatarType: AvatarType, + forcedAvatarSize: Dp?, + modifier: Modifier = Modifier.Companion, + contentDescription: String? = null, +) { + val size = forcedAvatarSize ?: avatarData.size.dp + SubcomposeAsyncImage( + model = avatarData, + contentDescription = contentDescription, + contentScale = ContentScale.Companion.Crop, + modifier = modifier + .size(size) + .clip(avatarShape(avatarType)) + ) { + val collectedState by painter.state.collectAsState() + when (val state = collectedState) { + is AsyncImagePainter.State.Success -> SubcomposeAsyncImageContent() + is AsyncImagePainter.State.Error -> { + SideEffect { + Timber.Forest.e( + state.result.throwable, + "Error loading avatar $state\n${state.result}" + ) + } + InitialLetterAvatar( + avatarData = avatarData, + avatarType = avatarType, + forcedAvatarSize = forcedAvatarSize, + contentDescription = contentDescription, + ) + } + else -> InitialLetterAvatar( + avatarData = avatarData, + avatarType = avatarType, + forcedAvatarSize = forcedAvatarSize, + contentDescription = contentDescription, + ) + } + } +} diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/InitialLetterAvatar.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/InitialLetterAvatar.kt new file mode 100644 index 0000000000..4c54d337ef --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/InitialLetterAvatar.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.designsystem.components.avatar + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.Dp +import io.element.android.libraries.designsystem.colors.AvatarColorsProvider + +@Composable +internal fun InitialLetterAvatar( + avatarData: AvatarData, + avatarType: AvatarType, + forcedAvatarSize: Dp?, + contentDescription: String?, + modifier: Modifier = Modifier.Companion, +) { + val avatarColors = AvatarColorsProvider.provide(avatarData.id) + TextAvatar( + text = avatarData.initialLetter, + size = forcedAvatarSize ?: avatarData.size.dp, + avatarType = avatarType, + colors = avatarColors, + contentDescription = contentDescription, + modifier = modifier + ) +}