mirror of
https://github.com/fromchat-messenger/app.git
synced 2026-09-22 19:15:05 +03:00
88 lines
2.8 KiB
Kotlin
88 lines
2.8 KiB
Kotlin
package ru.fromchat.ui.chat
|
|
|
|
import androidx.compose.animation.core.animateFloatAsState
|
|
import androidx.compose.animation.core.tween
|
|
import androidx.compose.foundation.background
|
|
import androidx.compose.foundation.layout.Box
|
|
import androidx.compose.foundation.layout.size
|
|
import androidx.compose.foundation.shape.CircleShape
|
|
import androidx.compose.material3.MaterialTheme
|
|
import androidx.compose.material3.Text
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.runtime.getValue
|
|
import androidx.compose.runtime.mutableStateOf
|
|
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.clip
|
|
import androidx.compose.ui.graphics.Color
|
|
import androidx.compose.ui.layout.ContentScale
|
|
import androidx.compose.ui.text.font.FontWeight
|
|
import androidx.compose.ui.unit.Dp
|
|
import androidx.compose.ui.unit.dp
|
|
import coil3.compose.AsyncImage
|
|
import ru.fromchat.core.config.Config
|
|
|
|
@Composable
|
|
fun Avatar(
|
|
profilePictureUrl: String?,
|
|
displayName: String,
|
|
size: Dp = 32.dp,
|
|
modifier: Modifier = Modifier
|
|
) {
|
|
var imageLoadFailed by remember { mutableStateOf(false) }
|
|
val alpha by animateFloatAsState(
|
|
targetValue = if (imageLoadFailed) 0f else 1f,
|
|
animationSpec = tween(300),
|
|
label = "avatar_fade"
|
|
)
|
|
|
|
val gradient = remember(displayName) { generateGradientFromName(displayName) }
|
|
val initials = remember(displayName) { getInitials(displayName) }
|
|
|
|
Box(
|
|
modifier = modifier
|
|
.size(size)
|
|
.clip(CircleShape)
|
|
.background(gradient),
|
|
contentAlignment = Alignment.Center
|
|
) {
|
|
if (profilePictureUrl != null && !imageLoadFailed) {
|
|
val fullUrl = if (profilePictureUrl.startsWith("http")) {
|
|
profilePictureUrl
|
|
} else {
|
|
"${Config.getApiBaseUrl()}$profilePictureUrl"
|
|
}
|
|
|
|
AsyncImage(
|
|
model = fullUrl,
|
|
contentDescription = displayName,
|
|
modifier = Modifier
|
|
.size(size)
|
|
.clip(CircleShape),
|
|
contentScale = ContentScale.Crop,
|
|
onError = {
|
|
imageLoadFailed = true
|
|
},
|
|
onSuccess = {
|
|
imageLoadFailed = false
|
|
}
|
|
)
|
|
}
|
|
|
|
// Fallback initials
|
|
if (imageLoadFailed || profilePictureUrl == null) {
|
|
Text(
|
|
text = initials,
|
|
style = MaterialTheme.typography.bodyMedium,
|
|
fontWeight = FontWeight.SemiBold,
|
|
color = Color.White,
|
|
modifier = Modifier
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
|