feat: Add dropdown menu for chat options and confirmation dialogs for delete and block actions

This commit is contained in:
k1ngsterr1
2026-01-12 01:55:44 +05:00
parent a75dfaab98
commit 5f348f329e

View File

@@ -54,6 +54,10 @@ import com.rosetta.messenger.ui.components.AppleEmojiText
import com.rosetta.messenger.ui.components.AppleEmojiTextField
import com.rosetta.messenger.ui.components.VerifiedBadge
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
import android.view.inputmethod.InputMethodManager
import android.content.Context
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import java.text.SimpleDateFormat
import java.util.*
import kotlinx.coroutines.delay
@@ -227,6 +231,11 @@ fun ChatDetailScreen(
// val debugLogs by ProtocolManager.debugLogs.collectAsState()
val debugLogs = remember { emptyList<String>() }
// Состояние выпадающего меню
var showMenu by remember { mutableStateOf(false) }
var showDeleteConfirm by remember { mutableStateOf(false) }
var showBlockConfirm by remember { mutableStateOf(false) }
// Подключаем к ViewModel
val messages by viewModel.messages.collectAsState()
val inputText by viewModel.inputText.collectAsState()
@@ -446,11 +455,13 @@ fun ChatDetailScreen(
)
}
// Кнопка меню с выпадающим списком
Box {
IconButton(
onClick = {
keyboardController?.hide()
focusManager.clearFocus()
/* TODO: More options */
showMenu = true
}
) {
Icon(
@@ -459,6 +470,68 @@ fun ChatDetailScreen(
tint = textColor
)
}
// Выпадающее меню
DropdownMenu(
expanded = showMenu,
onDismissRequest = { showMenu = false },
modifier = Modifier
.background(
color = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
shape = RoundedCornerShape(12.dp)
)
) {
// Delete Chat
DropdownMenuItem(
text = {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
Icons.Default.Delete,
contentDescription = null,
tint = PrimaryBlue,
modifier = Modifier.size(20.dp)
)
Spacer(modifier = Modifier.width(12.dp))
Text(
"Delete Chat",
color = textColor,
fontSize = 16.sp
)
}
},
onClick = {
showMenu = false
showDeleteConfirm = true
}
)
// Block User (не показываем для Saved Messages)
if (!isSavedMessages) {
DropdownMenuItem(
text = {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
Icons.Default.Block,
contentDescription = null,
tint = Color(0xFFFF3B30),
modifier = Modifier.size(20.dp)
)
Spacer(modifier = Modifier.width(12.dp))
Text(
"Block User",
color = Color(0xFFFF3B30),
fontSize = 16.sp
)
}
},
onClick = {
showMenu = false
showBlockConfirm = true
}
)
}
}
}
}
// Нижняя линия для разделения
Box(
@@ -725,6 +798,79 @@ fun ChatDetailScreen(
confirmButton = { TextButton(onClick = { showLogs = false }) { Text("Close") } }
)
}
// Диалог подтверждения удаления чата
if (showDeleteConfirm) {
AlertDialog(
onDismissRequest = { showDeleteConfirm = false },
containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
title = {
Text(
"Delete Chat",
fontWeight = FontWeight.Bold,
color = textColor
)
},
text = {
Text(
"Are you sure you want to delete this chat? This action cannot be undone.",
color = secondaryTextColor
)
},
confirmButton = {
TextButton(
onClick = {
showDeleteConfirm = false
// TODO: Implement delete chat
onBack()
}
) {
Text("Delete", color = Color(0xFFFF3B30))
}
},
dismissButton = {
TextButton(onClick = { showDeleteConfirm = false }) {
Text("Cancel", color = PrimaryBlue)
}
}
)
}
// Диалог подтверждения блокировки
if (showBlockConfirm) {
AlertDialog(
onDismissRequest = { showBlockConfirm = false },
containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
title = {
Text(
"Block ${user.title.ifEmpty { "User" }}",
fontWeight = FontWeight.Bold,
color = textColor
)
},
text = {
Text(
"Are you sure you want to block this user? They won't be able to send you messages.",
color = secondaryTextColor
)
},
confirmButton = {
TextButton(
onClick = {
showBlockConfirm = false
// TODO: Implement block user
}
) {
Text("Block", color = Color(0xFFFF3B30))
}
},
dismissButton = {
TextButton(onClick = { showBlockConfirm = false }) {
Text("Cancel", color = PrimaryBlue)
}
}
)
}
}
/** 🚀 Анимация появления сообщения Telegram-style */
@@ -900,9 +1046,16 @@ private fun MessageInputBar(
placeholderColor: Color
) {
var showEmojiPicker by remember { mutableStateOf(false) }
// Флаг для запуска закрытия клавиатуры перед открытием emoji picker
var pendingEmojiPicker by remember { mutableStateOf(false) }
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
val interactionSource = remember { MutableInteractionSource() }
val scope = rememberCoroutineScope()
// Получаем context и view для гарантированного закрытия клавиатуры
val context = LocalContext.current
val view = LocalView.current
// Состояние отправки
val canSend = remember(value) { value.isNotBlank() }
@@ -910,16 +1063,36 @@ private fun MessageInputBar(
// Easing анимации
val backEasing = CubicBezierEasing(0.34f, 1.56f, 0.64f, 1f)
// Функция для гарантированного закрытия клавиатуры через InputMethodManager
fun hideKeyboardCompletely() {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
focusManager.clearFocus(force = true)
}
// Эффект для закрытия клавиатуры и открытия emoji picker
LaunchedEffect(pendingEmojiPicker) {
if (pendingEmojiPicker) {
// Гарантированно закрываем клавиатуру через InputMethodManager
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
focusManager.clearFocus(force = true)
// Ждём пока клавиатура закроется
delay(200)
// Теперь открываем emoji picker
showEmojiPicker = true
pendingEmojiPicker = false
}
}
// Функция переключения emoji picker
fun toggleEmojiPicker() {
if (showEmojiPicker) {
// Закрываем emoji picker
showEmojiPicker = false
} else {
// Сначала скрываем клавиатуру, затем показываем emoji picker
focusManager.clearFocus(force = true)
keyboardController?.hide()
// Небольшая задержка чтобы клавиатура успела закрыться
showEmojiPicker = true
// Запускаем процесс: сначала закрыть клавиатуру, потом открыть picker
pendingEmojiPicker = true
}
}