feat: Update avatar behavior in CollapsingProfileHeader to handle presence of avatar for animations and haptic feedback

This commit is contained in:
k1ngsterr1
2026-01-31 03:52:35 +05:00
parent 0cb8573efc
commit e9386c21dc

View File

@@ -751,17 +751,19 @@ private fun CollapsingProfileHeader(
// ═══════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════
// 👤 AVATAR - По умолчанию КРУГЛАЯ, при overscroll расширяется до прямоугольника // 👤 AVATAR - По умолчанию КРУГЛАЯ, при overscroll расширяется до прямоугольника
// При collapse - уменьшается и уходит вверх // При collapse - уменьшается и уходит вверх
// ТОЛЬКО ЕСЛИ ЕСТЬ АВАТАРКА! Без аватарки всегда круг
// ═══════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════
val circleSize = AVATAR_SIZE_EXPANDED val circleSize = AVATAR_SIZE_EXPANDED
// Зона аватарки = ВСЯ высота header включая статус бар // Зона аватарки = ВСЯ высота header включая статус бар
val avatarZoneHeight = EXPANDED_HEADER_HEIGHT + statusBarHeight val avatarZoneHeight = EXPANDED_HEADER_HEIGHT + statusBarHeight
// При overscroll расширяем до прямоугольника на всю зону (только если не collapsed) // При overscroll расширяем до прямоугольника на всю зону (только если не collapsed И есть
// аватарка)
val avatarWidth: Dp val avatarWidth: Dp
val avatarHeight: Dp val avatarHeight: Dp
if (collapseProgress < 0.1f && expansionProgress > 0f) { if (hasAvatar && collapseProgress < 0.1f && expansionProgress > 0f) {
// Overscroll: круг -> прямоугольник на всю зону ВКЛЮЧАЯ статус бар // Overscroll: круг -> прямоугольник на всю зону ВКЛЮЧАЯ статус бар (ТОЛЬКО С АВАТАРКОЙ)
avatarWidth = androidx.compose.ui.unit.lerp(circleSize, screenWidthDp, expansionProgress) avatarWidth = androidx.compose.ui.unit.lerp(circleSize, screenWidthDp, expansionProgress)
avatarHeight = avatarHeight =
androidx.compose.ui.unit.lerp(circleSize, avatarZoneHeight, expansionProgress) androidx.compose.ui.unit.lerp(circleSize, avatarZoneHeight, expansionProgress)
@@ -783,8 +785,8 @@ private fun CollapsingProfileHeader(
val topAvatarY = 0.dp // От самого верха экрана при полном expansion val topAvatarY = 0.dp // От самого верха экрана при полном expansion
val avatarY = val avatarY =
if (collapseProgress < 0.1f && expansionProgress > 0f) { if (hasAvatar && collapseProgress < 0.1f && expansionProgress > 0f) {
// При overscroll прижимаемся к самому верху // При overscroll прижимаемся к самому верху (ТОЛЬКО С АВАТАРКОЙ)
androidx.compose.ui.unit.lerp(defaultCenterY, topAvatarY, expansionProgress) androidx.compose.ui.unit.lerp(defaultCenterY, topAvatarY, expansionProgress)
} else { } else {
// Collapse: сразу начинаем уходить вверх // Collapse: сразу начинаем уходить вверх
@@ -795,9 +797,10 @@ private fun CollapsingProfileHeader(
) )
} }
// Закругление: круг по умолчанию, при overscroll становится квадратом БЕЗ скругления // Закругление: круг по умолчанию, при overscroll становится квадратом БЕЗ скругления (ТОЛЬКО С
// АВАТАРКОЙ)
val cornerRadius = val cornerRadius =
if (collapseProgress < 0.1f && expansionProgress > 0f) { if (hasAvatar && collapseProgress < 0.1f && expansionProgress > 0f) {
// Overscroll: круг -> квадрат без скругления // Overscroll: круг -> квадрат без скругления
androidx.compose.ui.unit.lerp(avatarSize / 2, 0.dp, expansionProgress) androidx.compose.ui.unit.lerp(avatarSize / 2, 0.dp, expansionProgress)
} else { } else {
@@ -805,12 +808,12 @@ private fun CollapsingProfileHeader(
avatarSize / 2 avatarSize / 2
} }
// Haptic feedback при достижении полного квадрата // Haptic feedback при достижении полного квадрата (ТОЛЬКО С АВАТАРКОЙ)
val hapticFeedback = LocalHapticFeedback.current val hapticFeedback = LocalHapticFeedback.current
var hasTriggeredHaptic by remember { mutableStateOf(false) } var hasTriggeredHaptic by remember { mutableStateOf(false) }
LaunchedEffect(expansionProgress) { LaunchedEffect(expansionProgress, hasAvatar) {
if (expansionProgress >= 0.95f && !hasTriggeredHaptic) { if (hasAvatar && expansionProgress >= 0.95f && !hasTriggeredHaptic) {
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
hasTriggeredHaptic = true hasTriggeredHaptic = true
} else if (expansionProgress < 0.5f) { } else if (expansionProgress < 0.5f) {
@@ -846,36 +849,44 @@ private fun CollapsingProfileHeader(
) )
// ═══════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════
// 👤 AVATAR - Круг по умолчанию, квадрат при overscroll // 👤 AVATAR - Круг по умолчанию, квадрат при overscroll (ТОЛЬКО С АВАТАРКОЙ)
// Без аватарки - всегда круглый placeholder как в sidebar
// ═══════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════
if (avatarSize > 1.dp) { if (avatarSize > 1.dp) {
Box( if (hasAvatar) {
modifier = // С аватаркой - расширяется до квадрата
Modifier.offset(x = avatarX, y = avatarY) Box(
.size(width = avatarWidth, height = avatarHeight) modifier =
.clip(RoundedCornerShape(cornerRadius)), Modifier.offset(x = avatarX, y = avatarY)
contentAlignment = Alignment.Center .size(width = avatarWidth, height = avatarHeight)
) { .clip(RoundedCornerShape(cornerRadius)),
if (avatarRepository != null) { contentAlignment = Alignment.Center
FullSizeAvatar( ) {
publicKey = publicKey, if (avatarRepository != null) {
avatarRepository = avatarRepository, FullSizeAvatar(
isDarkTheme = isDarkTheme publicKey = publicKey,
) avatarRepository = avatarRepository,
} else { isDarkTheme = isDarkTheme
Box( )
modifier = }
Modifier.fillMaxSize().background(avatarColors.backgroundColor), }
contentAlignment = Alignment.Center } else {
) { // Без аватарки - ВСЕГДА круглый placeholder как в sidebar
if (avatarFontSize > 1.sp) { Box(
Text( modifier =
text = getInitials(name), Modifier.offset(x = avatarX, y = avatarY)
fontSize = avatarFontSize, .size(avatarSize)
fontWeight = FontWeight.Bold, .clip(CircleShape)
color = avatarColors.textColor .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)) Spacer(modifier = Modifier.height(2.dp))
Text(text = "online", fontSize = onlineFontSize, color = Color(0xFF4CAF50)) Text(text = "online", fontSize = onlineFontSize, color = Color.White)
} }
} }
} }