Skip to content

Commit 8128a59

Browse files
authored
Merge pull request #2667 from SpiritCroc/avatar-fallback
Fall back to initials avatar when image avatar doesn't work
2 parents b6ceb8c + e4b76e0 commit 8128a59

File tree

2 files changed

+34
-10
lines changed
  • changelog.d
  • libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar

2 files changed

+34
-10
lines changed

changelog.d/2667.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fall back to name-based generated avatars when image avatars don't load.

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

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,21 @@ import androidx.compose.foundation.layout.Row
2323
import androidx.compose.foundation.layout.size
2424
import androidx.compose.foundation.shape.CircleShape
2525
import androidx.compose.runtime.Composable
26+
import androidx.compose.runtime.SideEffect
2627
import androidx.compose.ui.Alignment
2728
import androidx.compose.ui.Modifier
2829
import androidx.compose.ui.draw.clip
2930
import androidx.compose.ui.layout.ContentScale
31+
import androidx.compose.ui.platform.LocalInspectionMode
3032
import androidx.compose.ui.semantics.clearAndSetSemantics
3133
import androidx.compose.ui.tooling.preview.Preview
3234
import androidx.compose.ui.tooling.preview.PreviewParameter
3335
import androidx.compose.ui.unit.dp
3436
import androidx.compose.ui.unit.sp
3537
import coil.compose.AsyncImage
38+
import coil.compose.AsyncImagePainter
39+
import coil.compose.SubcomposeAsyncImage
40+
import coil.compose.SubcomposeAsyncImageContent
3641
import io.element.android.compound.theme.ElementTheme
3742
import io.element.android.libraries.designsystem.colors.AvatarColorsProvider
3843
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
@@ -71,16 +76,34 @@ private fun ImageAvatar(
7176
modifier: Modifier = Modifier,
7277
contentDescription: String? = null,
7378
) {
74-
AsyncImage(
75-
model = avatarData,
76-
onError = {
77-
Timber.e(it.result.throwable, "Error loading avatar $it\n${it.result}")
78-
},
79-
contentDescription = contentDescription,
80-
contentScale = ContentScale.Crop,
81-
placeholder = debugPlaceholderAvatar(),
82-
modifier = modifier
83-
)
79+
if (LocalInspectionMode.current) {
80+
// For compose previews, use debugPlaceholderAvatar()
81+
// instead of falling back to initials avatar on load failure
82+
AsyncImage(
83+
model = avatarData,
84+
contentDescription = contentDescription,
85+
placeholder = debugPlaceholderAvatar(),
86+
modifier = modifier
87+
)
88+
} else {
89+
SubcomposeAsyncImage(
90+
model = avatarData,
91+
contentDescription = contentDescription,
92+
contentScale = ContentScale.Crop,
93+
modifier = modifier
94+
) {
95+
when (val state = painter.state) {
96+
is AsyncImagePainter.State.Success -> SubcomposeAsyncImageContent()
97+
is AsyncImagePainter.State.Error -> {
98+
SideEffect {
99+
Timber.e(state.result.throwable, "Error loading avatar $state\n${state.result}")
100+
}
101+
InitialsAvatar(avatarData = avatarData)
102+
}
103+
else -> InitialsAvatar(avatarData = avatarData)
104+
}
105+
}
106+
}
84107
}
85108

86109
@Composable

0 commit comments

Comments
 (0)