feat: add animated badge for top-level requests count in ChatsListScreen
This commit is contained in:
@@ -42,34 +42,63 @@ fun BoxScope.BlurredAvatarBackground(
|
||||
overlayColors: List<Color>? = null,
|
||||
isDarkTheme: Boolean = true
|
||||
) {
|
||||
// В светлой теме: если дефолтный фон (avatar) — синий как шапка chat list,
|
||||
// если выбран кастомный цвет в Appearance — используем его
|
||||
if (!isDarkTheme) {
|
||||
val lightBgModifier = if (overlayColors != null && overlayColors.isNotEmpty()) {
|
||||
if (overlayColors.size == 1) {
|
||||
Modifier.matchParentSize().background(overlayColors[0])
|
||||
} else {
|
||||
Modifier.matchParentSize().background(
|
||||
Brush.linearGradient(colors = overlayColors)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Modifier.matchParentSize().background(Color(0xFF0D8CF4))
|
||||
}
|
||||
Box(modifier = lightBgModifier)
|
||||
// В светлой теме с дефолтным фоном (avatar, без overlay) — синий как шапка chat list
|
||||
if (!isDarkTheme && (overlayColors == null || overlayColors.isEmpty())) {
|
||||
Box(modifier = Modifier.matchParentSize().background(Color(0xFF0D8CF4)))
|
||||
return
|
||||
}
|
||||
|
||||
// Если выбран цвет в Appearance — просто сплошной цвет/градиент, без blur
|
||||
// Если выбран цвет в Appearance — рисуем блюр аватарки + полупрозрачный overlay поверх
|
||||
// (одинаково для светлой и тёмной темы, чтобы цвет совпадал с превью в Appearance)
|
||||
if (overlayColors != null && overlayColors.isNotEmpty()) {
|
||||
val bgModifier = if (overlayColors.size == 1) {
|
||||
Modifier.matchParentSize().background(overlayColors[0])
|
||||
// Загружаем блюр аватарки для подложки
|
||||
val avatarsForOverlay by avatarRepository?.getAvatars(publicKey, allDecode = false)?.collectAsState()
|
||||
?: remember { mutableStateOf(emptyList()) }
|
||||
val avatarKeyForOverlay = remember(avatarsForOverlay) {
|
||||
avatarsForOverlay.firstOrNull()?.timestamp ?: 0L
|
||||
}
|
||||
var blurredForOverlay by remember { mutableStateOf<Bitmap?>(null) }
|
||||
LaunchedEffect(avatarKeyForOverlay) {
|
||||
val currentAvatars = avatarsForOverlay
|
||||
if (currentAvatars.isNotEmpty()) {
|
||||
val original = withContext(Dispatchers.IO) {
|
||||
AvatarFileManager.base64ToBitmap(currentAvatars.first().base64Data)
|
||||
}
|
||||
if (original != null) {
|
||||
blurredForOverlay = withContext(Dispatchers.Default) {
|
||||
val scaled = Bitmap.createScaledBitmap(original, original.width / 4, original.height / 4, true)
|
||||
var result = scaled
|
||||
repeat(2) { result = fastBlur(result, (blurRadius / 4).toInt().coerceAtLeast(1)) }
|
||||
result
|
||||
}
|
||||
}
|
||||
} else {
|
||||
blurredForOverlay = null
|
||||
}
|
||||
}
|
||||
|
||||
// Подложка: блюр аватарки или fallback цвет
|
||||
Box(modifier = Modifier.matchParentSize()) {
|
||||
if (blurredForOverlay != null) {
|
||||
Image(
|
||||
bitmap = blurredForOverlay!!.asImageBitmap(),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxSize().graphicsLayer { this.alpha = 0.35f },
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Overlay — полупрозрачный, как в Appearance preview
|
||||
val overlayAlpha = if (blurredForOverlay != null) 0.55f else 0.85f
|
||||
val overlayMod = if (overlayColors.size == 1) {
|
||||
Modifier.matchParentSize().background(overlayColors[0].copy(alpha = overlayAlpha))
|
||||
} else {
|
||||
Modifier.matchParentSize().background(
|
||||
Brush.linearGradient(colors = overlayColors)
|
||||
Brush.linearGradient(colors = overlayColors.map { it.copy(alpha = overlayAlpha) })
|
||||
)
|
||||
}
|
||||
Box(modifier = bgModifier)
|
||||
Box(modifier = overlayMod)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user