feat: Add block/unblock functionality and profile menu in OtherProfileScreen
This commit is contained in:
@@ -770,6 +770,35 @@ fun ProfilePhotoMenu(
|
||||
}
|
||||
}
|
||||
|
||||
/** Other user profile menu with block option */
|
||||
@Composable
|
||||
fun OtherProfileMenu(
|
||||
expanded: Boolean,
|
||||
onDismiss: () -> Unit,
|
||||
isDarkTheme: Boolean,
|
||||
isBlocked: Boolean,
|
||||
onBlockClick: () -> Unit
|
||||
) {
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = onDismiss,
|
||||
modifier = Modifier.width(220.dp),
|
||||
properties = PopupProperties(
|
||||
focusable = true,
|
||||
dismissOnBackPress = true,
|
||||
dismissOnClickOutside = true
|
||||
)
|
||||
) {
|
||||
ProfilePhotoMenuItem(
|
||||
icon = if (isBlocked) Icons.Default.CheckCircle else Icons.Default.Block,
|
||||
text = if (isBlocked) "Unblock User" else "Block User",
|
||||
onClick = onBlockClick,
|
||||
tintColor = if (isBlocked) Color(0xFF4CAF50) else Color(0xFFFF3B30),
|
||||
textColor = if (isBlocked) Color(0xFF4CAF50) else Color(0xFFFF3B30)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ProfilePhotoMenuItem(
|
||||
icon: ImageVector,
|
||||
|
||||
@@ -29,6 +29,7 @@ import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -140,19 +141,6 @@ fun OtherProfileScreen(
|
||||
isDarkTheme = isDarkTheme
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 🚫 BLOCK SECTION
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
TelegramSectionTitle(title = "Privacy", isDarkTheme = isDarkTheme)
|
||||
|
||||
TelegramBlockItem(
|
||||
isBlocked = isBlocked,
|
||||
onToggle = { isBlocked = !isBlocked },
|
||||
isDarkTheme = isDarkTheme
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
}
|
||||
}
|
||||
@@ -169,7 +157,9 @@ fun OtherProfileScreen(
|
||||
onBack = onBack,
|
||||
isDarkTheme = isDarkTheme,
|
||||
showAvatarMenu = showAvatarMenu,
|
||||
onAvatarMenuChange = { showAvatarMenu = it }
|
||||
onAvatarMenuChange = { showAvatarMenu = it },
|
||||
isBlocked = isBlocked,
|
||||
onBlockToggle = { isBlocked = !isBlocked }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -186,7 +176,9 @@ private fun CollapsingOtherProfileHeader(
|
||||
onBack: () -> Unit,
|
||||
isDarkTheme: Boolean,
|
||||
showAvatarMenu: Boolean,
|
||||
onAvatarMenuChange: (Boolean) -> Unit
|
||||
onAvatarMenuChange: (Boolean) -> Unit,
|
||||
isBlocked: Boolean,
|
||||
onBlockToggle: () -> Unit
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
val configuration = LocalConfiguration.current
|
||||
@@ -208,108 +200,47 @@ private fun CollapsingOtherProfileHeader(
|
||||
val avatarFontSize = androidx.compose.ui.unit.lerp(40.sp, 0.sp, collapseProgress)
|
||||
|
||||
// Text animation - always centered
|
||||
val textX = screenWidthDp / 2 // Always center
|
||||
|
||||
val textExpandedY = statusBarHeight + 32.dp + AVATAR_SIZE_EXPANDED_OTHER + 48.dp
|
||||
val textCollapsedY = statusBarHeight + (COLLAPSED_HEADER_HEIGHT_OTHER - 40.dp) / 2
|
||||
val textCollapsedY = statusBarHeight + COLLAPSED_HEADER_HEIGHT_OTHER / 2
|
||||
val textY = androidx.compose.ui.unit.lerp(textExpandedY, textCollapsedY, collapseProgress)
|
||||
|
||||
val nameFontSize = androidx.compose.ui.unit.lerp(24.sp, 17.sp, collapseProgress)
|
||||
val usernameFontSize = androidx.compose.ui.unit.lerp(15.sp, 13.sp, collapseProgress)
|
||||
|
||||
val headerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White
|
||||
val nameFontSize = androidx.compose.ui.unit.lerp(24.sp, 18.sp, collapseProgress)
|
||||
val onlineFontSize = androidx.compose.ui.unit.lerp(14.sp, 13.sp, collapseProgress)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(headerHeight)
|
||||
.background(headerColor)
|
||||
.drawBehind {
|
||||
drawRect(avatarColors.backgroundColor)
|
||||
}
|
||||
) {
|
||||
// Background color
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 🔙 BACK BUTTON
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(headerColor)
|
||||
)
|
||||
|
||||
// Avatar
|
||||
if (avatarSize > 0.dp) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.offset {
|
||||
IntOffset(
|
||||
with(density) { avatarCenterX.toPx().roundToInt() },
|
||||
with(density) { avatarY.toPx().roundToInt() }
|
||||
)
|
||||
}
|
||||
.size(avatarSize)
|
||||
.clip(CircleShape)
|
||||
.background(avatarColors.backgroundColor),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (avatarFontSize.value > 0) {
|
||||
Text(
|
||||
text = getInitials(name),
|
||||
fontSize = avatarFontSize,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = avatarColors.textColor
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Name and username - always centered
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
.offset(y = textY)
|
||||
.graphicsLayer {
|
||||
val centerOffsetY = with(density) {
|
||||
androidx.compose.ui.unit.lerp(24.dp, 18.dp, collapseProgress).toPx()
|
||||
}
|
||||
translationY = -centerOffsetY
|
||||
},
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
.padding(top = statusBarHeight)
|
||||
.padding(start = 4.dp, top = 4.dp)
|
||||
.size(48.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = name,
|
||||
fontSize = nameFontSize,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = if (isDarkTheme) Color.White else Color.Black,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
|
||||
if (username.isNotEmpty() && collapseProgress < 0.9f) {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = "@$username",
|
||||
fontSize = usernameFontSize,
|
||||
color = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.graphicsLayer {
|
||||
alpha = 1f - (collapseProgress * 2f).coerceIn(0f, 1f)
|
||||
}
|
||||
IconButton(
|
||||
onClick = onBack,
|
||||
modifier = Modifier.size(48.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.ArrowBack,
|
||||
contentDescription = "Back",
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Back button
|
||||
IconButton(
|
||||
onClick = onBack,
|
||||
modifier = Modifier
|
||||
.padding(top = statusBarHeight)
|
||||
.padding(start = 4.dp, top = 4.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.ArrowBack,
|
||||
contentDescription = "Back",
|
||||
tint = if (isDarkTheme) Color.White else Color.Black
|
||||
)
|
||||
}
|
||||
|
||||
// Menu button (top right corner)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// ⋮ MENU BUTTON (top right corner)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
@@ -325,22 +256,88 @@ private fun CollapsingOtherProfileHeader(
|
||||
Icon(
|
||||
imageVector = Icons.Default.MoreVert,
|
||||
contentDescription = "Profile menu",
|
||||
tint = if (isDarkTheme) Color.White else Color.Black,
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
|
||||
// Меню для установки фото профиля
|
||||
com.rosetta.messenger.ui.chats.components.ProfilePhotoMenu(
|
||||
// Меню с блокировкой пользователя
|
||||
com.rosetta.messenger.ui.chats.components.OtherProfileMenu(
|
||||
expanded = showAvatarMenu,
|
||||
onDismiss = { onAvatarMenuChange(false) },
|
||||
isDarkTheme = isDarkTheme,
|
||||
onSetPhotoClick = {
|
||||
isBlocked = isBlocked,
|
||||
onBlockClick = {
|
||||
onAvatarMenuChange(false)
|
||||
// TODO: Реализовать выбор фото профиля
|
||||
onBlockToggle()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 👤 AVATAR - shrinks and moves up
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
if (avatarSize > 1.dp) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.offset(
|
||||
x = avatarCenterX + (AVATAR_SIZE_EXPANDED_OTHER - avatarSize) / 2,
|
||||
y = avatarY
|
||||
)
|
||||
.size(avatarSize)
|
||||
.clip(CircleShape)
|
||||
.background(Color.White.copy(alpha = 0.15f))
|
||||
.padding(2.dp)
|
||||
.clip(CircleShape)
|
||||
.background(avatarColors.backgroundColor),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (avatarFontSize > 1.sp) {
|
||||
Text(
|
||||
text = getInitials(name),
|
||||
fontSize = avatarFontSize,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = avatarColors.textColor
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 📝 TEXT BLOCK - Name + Online, always centered
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
.offset(y = textY)
|
||||
.graphicsLayer {
|
||||
val centerOffsetY = with(density) {
|
||||
androidx.compose.ui.unit.lerp(24.dp, 18.dp, collapseProgress).toPx()
|
||||
}
|
||||
translationY = -centerOffsetY
|
||||
},
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(
|
||||
text = name,
|
||||
fontSize = nameFontSize,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = Color.White,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.widthIn(max = 220.dp),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
|
||||
// Online text - always centered
|
||||
Text(
|
||||
text = "online",
|
||||
fontSize = onlineFontSize,
|
||||
color = Color(0xFF4CAF50)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user