feat: simplify color handling in ChatsListScreen and improve gesture callbacks in SwipeableDialogItem

This commit is contained in:
2026-02-12 20:09:53 +05:00
parent ea537ccce1
commit e208ce050a
16 changed files with 419 additions and 365 deletions

View File

@@ -38,37 +38,63 @@ fun BoxScope.BlurredAvatarBackground(
avatarRepository: AvatarRepository?,
fallbackColor: Color,
blurRadius: Float = 25f,
alpha: Float = 0.3f,
overlayColors: List<Color>? = null
alpha: Float = 0.9f,
overlayColors: List<Color>? = null,
isDarkTheme: Boolean = true
) {
// Получаем аватары из репозитория
val avatars by avatarRepository?.getAvatars(publicKey, allDecode = false)?.collectAsState()
// В светлой теме: если дефолтный фон (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)
return
}
// Если выбран цвет в Appearance — просто сплошной цвет/градиент, без blur
if (overlayColors != null && overlayColors.isNotEmpty()) {
val bgModifier = if (overlayColors.size == 1) {
Modifier.matchParentSize().background(overlayColors[0])
} else {
Modifier.matchParentSize().background(
Brush.linearGradient(colors = overlayColors)
)
}
Box(modifier = bgModifier)
return
}
// Нет фона (avatar default) — blur аватарки
val avatars by avatarRepository?.getAvatars(publicKey, allDecode = false)?.collectAsState()
?: remember { mutableStateOf(emptyList()) }
// Состояние для bitmap и размытого bitmap
var originalBitmap by remember(avatars) { mutableStateOf<Bitmap?>(null) }
var blurredBitmap by remember(avatars) { mutableStateOf<Bitmap?>(null) }
// Декодируем и размываем аватар
LaunchedEffect(avatars) {
if (avatars.isNotEmpty()) {
originalBitmap = withContext(Dispatchers.IO) {
AvatarFileManager.base64ToBitmap(avatars.first().base64Data)
}
// Размываем bitmap (уменьшаем для производительности, затем применяем blur)
originalBitmap?.let { bitmap ->
blurredBitmap = withContext(Dispatchers.Default) {
// Уменьшаем размер для быстрого blur
val scaledBitmap = Bitmap.createScaledBitmap(
bitmap,
bitmap.width / 4,
bitmap.height / 4,
true
)
// Применяем blur несколько раз для более гладкого эффекта
var result = scaledBitmap
repeat(3) {
repeat(2) {
result = fastBlur(result, (blurRadius / 4).toInt().coerceAtLeast(1))
}
result
@@ -79,71 +105,22 @@ fun BoxScope.BlurredAvatarBackground(
blurredBitmap = null
}
}
// Используем matchParentSize() чтобы занимать только размер родителя
Box(modifier = Modifier.matchParentSize()) {
if (blurredBitmap != null) {
// Показываем размытое изображение
Image(
bitmap = blurredBitmap!!.asImageBitmap(),
contentDescription = null,
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
this.alpha = alpha
},
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop
)
// Дополнительный overlay — кастомный или стандартный
if (overlayColors != null && overlayColors.isNotEmpty()) {
// Кастомный цветной overlay
val overlayModifier = if (overlayColors.size == 1) {
Modifier
.fillMaxSize()
.background(overlayColors[0].copy(alpha = 0.55f))
} else {
Modifier
.fillMaxSize()
.background(
Brush.linearGradient(
colors = overlayColors.map { it.copy(alpha = 0.55f) }
)
)
}
Box(modifier = overlayModifier)
} else {
// Стандартный overlay для затемнения
Box(
modifier = Modifier
.fillMaxSize()
.background(fallbackColor.copy(alpha = 0.3f))
)
}
} else {
// Fallback: когда нет аватарки
if (overlayColors != null && overlayColors.isNotEmpty()) {
// Кастомный фон без blur
val bgModifier = if (overlayColors.size == 1) {
Modifier
.fillMaxSize()
.background(overlayColors[0])
} else {
Modifier
.fillMaxSize()
.background(
Brush.linearGradient(colors = overlayColors)
)
}
Box(modifier = bgModifier)
} else {
// Стандартный fallback: цветной фон
Box(
modifier = Modifier
.fillMaxSize()
.background(fallbackColor)
)
}
// Нет фото — цвет аватарки
Box(
modifier = Modifier
.fillMaxSize()
.background(fallbackColor)
)
}
}
}