diff --git a/changelog.d/2667.bugfix b/changelog.d/2667.bugfix new file mode 100644 index 0000000000..f72b79503f --- /dev/null +++ b/changelog.d/2667.bugfix @@ -0,0 +1 @@ +Fall back to name-based generated avatars when image avatars don't load. 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 b1e7bc6be0..173716aee3 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 @@ -23,16 +23,21 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect 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.platform.LocalInspectionMode import androidx.compose.ui.semantics.clearAndSetSemantics 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.sp import coil.compose.AsyncImage +import coil.compose.AsyncImagePainter +import coil.compose.SubcomposeAsyncImage +import coil.compose.SubcomposeAsyncImageContent import io.element.android.compound.theme.ElementTheme import io.element.android.libraries.designsystem.colors.AvatarColorsProvider import io.element.android.libraries.designsystem.preview.ElementThemedPreview @@ -71,16 +76,34 @@ private fun ImageAvatar( modifier: Modifier = Modifier, contentDescription: String? = null, ) { - AsyncImage( - model = avatarData, - onError = { - Timber.e(it.result.throwable, "Error loading avatar $it\n${it.result}") - }, - contentDescription = contentDescription, - contentScale = ContentScale.Crop, - placeholder = debugPlaceholderAvatar(), - modifier = modifier - ) + if (LocalInspectionMode.current) { + // For compose previews, use debugPlaceholderAvatar() + // instead of falling back to initials avatar on load failure + AsyncImage( + model = avatarData, + contentDescription = contentDescription, + placeholder = debugPlaceholderAvatar(), + modifier = modifier + ) + } else { + SubcomposeAsyncImage( + model = avatarData, + contentDescription = contentDescription, + contentScale = ContentScale.Crop, + modifier = modifier + ) { + when (val state = painter.state) { + is AsyncImagePainter.State.Success -> SubcomposeAsyncImageContent() + is AsyncImagePainter.State.Error -> { + SideEffect { + Timber.e(state.result.throwable, "Error loading avatar $state\n${state.result}") + } + InitialsAvatar(avatarData = avatarData) + } + else -> InitialsAvatar(avatarData = avatarData) + } + } + } } @Composable