From e9386c21dcef4ee2d4936c4245541b59c7952804 Mon Sep 17 00:00:00 2001 From: k1ngsterr1 Date: Sat, 31 Jan 2026 03:52:35 +0500 Subject: [PATCH] feat: Update avatar behavior in CollapsingProfileHeader to handle presence of avatar for animations and haptic feedback --- .../messenger/ui/settings/ProfileScreen.kt | 89 +++++++++++-------- 1 file changed, 50 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileScreen.kt index e757bc6..ee68575 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileScreen.kt @@ -751,17 +751,19 @@ private fun CollapsingProfileHeader( // ═══════════════════════════════════════════════════════════ // 👤 AVATAR - По умолчанию КРУГЛАЯ, при overscroll расширяется до прямоугольника // При collapse - уменьшается и уходит вверх + // ТОЛЬКО ЕСЛИ ЕСТЬ АВАТАРКА! Без аватарки всегда круг // ═══════════════════════════════════════════════════════════ val circleSize = AVATAR_SIZE_EXPANDED // Зона аватарки = ВСЯ высота header включая статус бар val avatarZoneHeight = EXPANDED_HEADER_HEIGHT + statusBarHeight - // При overscroll расширяем до прямоугольника на всю зону (только если не collapsed) + // При overscroll расширяем до прямоугольника на всю зону (только если не collapsed И есть + // аватарка) val avatarWidth: Dp val avatarHeight: Dp - if (collapseProgress < 0.1f && expansionProgress > 0f) { - // Overscroll: круг -> прямоугольник на всю зону ВКЛЮЧАЯ статус бар + if (hasAvatar && collapseProgress < 0.1f && expansionProgress > 0f) { + // Overscroll: круг -> прямоугольник на всю зону ВКЛЮЧАЯ статус бар (ТОЛЬКО С АВАТАРКОЙ) avatarWidth = androidx.compose.ui.unit.lerp(circleSize, screenWidthDp, expansionProgress) avatarHeight = androidx.compose.ui.unit.lerp(circleSize, avatarZoneHeight, expansionProgress) @@ -783,8 +785,8 @@ private fun CollapsingProfileHeader( val topAvatarY = 0.dp // От самого верха экрана при полном expansion val avatarY = - if (collapseProgress < 0.1f && expansionProgress > 0f) { - // При overscroll прижимаемся к самому верху + if (hasAvatar && collapseProgress < 0.1f && expansionProgress > 0f) { + // При overscroll прижимаемся к самому верху (ТОЛЬКО С АВАТАРКОЙ) androidx.compose.ui.unit.lerp(defaultCenterY, topAvatarY, expansionProgress) } else { // Collapse: сразу начинаем уходить вверх @@ -795,9 +797,10 @@ private fun CollapsingProfileHeader( ) } - // Закругление: круг по умолчанию, при overscroll становится квадратом БЕЗ скругления + // Закругление: круг по умолчанию, при overscroll становится квадратом БЕЗ скругления (ТОЛЬКО С + // АВАТАРКОЙ) val cornerRadius = - if (collapseProgress < 0.1f && expansionProgress > 0f) { + if (hasAvatar && collapseProgress < 0.1f && expansionProgress > 0f) { // Overscroll: круг -> квадрат без скругления androidx.compose.ui.unit.lerp(avatarSize / 2, 0.dp, expansionProgress) } else { @@ -805,12 +808,12 @@ private fun CollapsingProfileHeader( avatarSize / 2 } - // Haptic feedback при достижении полного квадрата + // Haptic feedback при достижении полного квадрата (ТОЛЬКО С АВАТАРКОЙ) val hapticFeedback = LocalHapticFeedback.current var hasTriggeredHaptic by remember { mutableStateOf(false) } - LaunchedEffect(expansionProgress) { - if (expansionProgress >= 0.95f && !hasTriggeredHaptic) { + LaunchedEffect(expansionProgress, hasAvatar) { + if (hasAvatar && expansionProgress >= 0.95f && !hasTriggeredHaptic) { hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) hasTriggeredHaptic = true } else if (expansionProgress < 0.5f) { @@ -846,36 +849,44 @@ private fun CollapsingProfileHeader( ) // ═══════════════════════════════════════════════════════════ - // 👤 AVATAR - Круг по умолчанию, квадрат при overscroll + // 👤 AVATAR - Круг по умолчанию, квадрат при overscroll (ТОЛЬКО С АВАТАРКОЙ) + // Без аватарки - всегда круглый placeholder как в sidebar // ═══════════════════════════════════════════════════════════ if (avatarSize > 1.dp) { - Box( - modifier = - Modifier.offset(x = avatarX, y = avatarY) - .size(width = avatarWidth, height = avatarHeight) - .clip(RoundedCornerShape(cornerRadius)), - contentAlignment = Alignment.Center - ) { - if (avatarRepository != null) { - FullSizeAvatar( - publicKey = publicKey, - avatarRepository = avatarRepository, - isDarkTheme = isDarkTheme - ) - } else { - Box( - modifier = - Modifier.fillMaxSize().background(avatarColors.backgroundColor), - contentAlignment = Alignment.Center - ) { - if (avatarFontSize > 1.sp) { - Text( - text = getInitials(name), - fontSize = avatarFontSize, - fontWeight = FontWeight.Bold, - color = avatarColors.textColor - ) - } + if (hasAvatar) { + // С аватаркой - расширяется до квадрата + Box( + modifier = + Modifier.offset(x = avatarX, y = avatarY) + .size(width = avatarWidth, height = avatarHeight) + .clip(RoundedCornerShape(cornerRadius)), + contentAlignment = Alignment.Center + ) { + if (avatarRepository != null) { + FullSizeAvatar( + publicKey = publicKey, + avatarRepository = avatarRepository, + isDarkTheme = isDarkTheme + ) + } + } + } else { + // Без аватарки - ВСЕГДА круглый placeholder как в sidebar + Box( + modifier = + Modifier.offset(x = avatarX, y = avatarY) + .size(avatarSize) + .clip(CircleShape) + .background(avatarColors.backgroundColor), + contentAlignment = Alignment.Center + ) { + if (avatarFontSize > 1.sp) { + Text( + text = getInitials(name), + fontSize = avatarFontSize, + fontWeight = FontWeight.Bold, + color = avatarColors.textColor + ) } } } @@ -984,7 +995,7 @@ private fun CollapsingProfileHeader( Spacer(modifier = Modifier.height(2.dp)) - Text(text = "online", fontSize = onlineFontSize, color = Color(0xFF4CAF50)) + Text(text = "online", fontSize = onlineFontSize, color = Color.White) } } }