feat: Update dialog deletion logic to use sorted dialog keys for message removal

This commit is contained in:
k1ngsterr1
2026-01-15 18:34:15 +05:00
parent 36976dc747
commit f2d744a442
2 changed files with 180 additions and 116 deletions

View File

@@ -211,6 +211,9 @@ fun ChatsListScreen(
var dialogToDelete by remember { mutableStateOf<DialogUiModel?>(null) }
var dialogToBlock by remember { mutableStateOf<DialogUiModel?>(null) }
var dialogToUnblock by remember { mutableStateOf<DialogUiModel?>(null) }
// Trigger для обновления статуса блокировки
var blocklistUpdateTrigger by remember { mutableStateOf(0) }
// Dev console dialog - commented out for now
/*
@@ -520,7 +523,7 @@ fun ChatsListScreen(
val isSavedMessages = dialog.opponentKey == accountPublicKey
// Check if user is blocked
var isBlocked by remember { mutableStateOf(false) }
LaunchedEffect(dialog.opponentKey) {
LaunchedEffect(dialog.opponentKey, blocklistUpdateTrigger) {
isBlocked = chatsViewModel.isUserBlocked(dialog.opponentKey)
}
@@ -577,37 +580,54 @@ fun ChatsListScreen(
)
},
text = {
val displayName = dialog.opponentTitle.ifEmpty { dialog.opponentKey.take(8) }
Text(
text = "All messages with $displayName will be permanently deleted. This action cannot be undone.",
fontSize = 15.sp,
color = if (isDarkTheme) Color(0xFFAAAAAA) else Color(0xFF666666),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
},
confirmButton = {
TextButton(
onClick = {
scope.launch {
chatsViewModel.deleteDialog(dialog.opponentKey)
dialogToDelete = null
}
},
colors = ButtonDefaults.textButtonColors(
contentColor = Color(0xFFFF3B30)
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
val displayName = dialog.opponentTitle.ifEmpty { dialog.opponentKey.take(8) }
Text(
text = "All messages with $displayName will be permanently deleted. This action cannot be undone.",
fontSize = 15.sp,
color = if (isDarkTheme) Color(0xFFAAAAAA) else Color(0xFF666666),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
) {
Text("Delete", fontWeight = FontWeight.SemiBold)
}
},
dismissButton = {
TextButton(
onClick = { dialogToDelete = null }
) {
Text("Cancel", fontWeight = FontWeight.Medium)
Spacer(modifier = Modifier.height(16.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
TextButton(
onClick = { dialogToDelete = null },
modifier = Modifier.weight(1f)
) {
Text("Cancel", fontWeight = FontWeight.Medium)
}
Spacer(modifier = Modifier.width(8.dp))
TextButton(
onClick = {
scope.launch {
chatsViewModel.deleteDialog(dialog.opponentKey)
dialogToDelete = null
}
},
colors = ButtonDefaults.textButtonColors(
contentColor = Color(0xFFFF3B30)
),
modifier = Modifier.weight(1f)
) {
Text("Delete", fontWeight = FontWeight.SemiBold)
}
}
}
},
confirmButton = {},
dismissButton = {},
containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
shape = RoundedCornerShape(16.dp)
)
@@ -635,37 +655,55 @@ fun ChatsListScreen(
)
},
text = {
val displayName = dialog.opponentTitle.ifEmpty { dialog.opponentKey.take(8) }
Text(
text = "$displayName will no longer be able to send you messages. You can unblock them later.",
fontSize = 15.sp,
color = if (isDarkTheme) Color(0xFFAAAAAA) else Color(0xFF666666),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
},
confirmButton = {
TextButton(
onClick = {
scope.launch {
chatsViewModel.blockUser(dialog.opponentKey)
dialogToBlock = null
}
},
colors = ButtonDefaults.textButtonColors(
contentColor = Color(0xFFFF3B30)
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
val displayName = dialog.opponentTitle.ifEmpty { dialog.opponentKey.take(8) }
Text(
text = "$displayName will no longer be able to send you messages. You can unblock them later.",
fontSize = 15.sp,
color = if (isDarkTheme) Color(0xFFAAAAAA) else Color(0xFF666666),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
) {
Text("Block", fontWeight = FontWeight.SemiBold)
}
},
dismissButton = {
TextButton(
onClick = { dialogToBlock = null }
) {
Text("Cancel", fontWeight = FontWeight.Medium)
Spacer(modifier = Modifier.height(16.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
TextButton(
onClick = { dialogToBlock = null },
modifier = Modifier.weight(1f)
) {
Text("Cancel", fontWeight = FontWeight.Medium)
}
Spacer(modifier = Modifier.width(8.dp))
TextButton(
onClick = {
scope.launch {
chatsViewModel.blockUser(dialog.opponentKey)
dialogToBlock = null
blocklistUpdateTrigger++
}
},
colors = ButtonDefaults.textButtonColors(
contentColor = Color(0xFFFF3B30)
),
modifier = Modifier.weight(1f)
) {
Text("Block", fontWeight = FontWeight.SemiBold)
}
}
}
},
confirmButton = {},
dismissButton = {},
containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
shape = RoundedCornerShape(16.dp)
)
@@ -693,37 +731,55 @@ fun ChatsListScreen(
)
},
text = {
val displayName = dialog.opponentTitle.ifEmpty { dialog.opponentKey.take(8) }
Text(
text = "$displayName will be able to send you messages again.",
fontSize = 15.sp,
color = if (isDarkTheme) Color(0xFFAAAAAA) else Color(0xFF666666),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
},
confirmButton = {
TextButton(
onClick = {
scope.launch {
chatsViewModel.unblockUser(dialog.opponentKey)
dialogToUnblock = null
}
},
colors = ButtonDefaults.textButtonColors(
contentColor = Color(0xFF4CAF50)
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
val displayName = dialog.opponentTitle.ifEmpty { dialog.opponentKey.take(8) }
Text(
text = "$displayName will be able to send you messages again.",
fontSize = 15.sp,
color = if (isDarkTheme) Color(0xFFAAAAAA) else Color(0xFF666666),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
) {
Text("Unblock", fontWeight = FontWeight.SemiBold)
}
},
dismissButton = {
TextButton(
onClick = { dialogToUnblock = null }
) {
Text("Cancel", fontWeight = FontWeight.Medium)
Spacer(modifier = Modifier.height(16.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
TextButton(
onClick = { dialogToUnblock = null },
modifier = Modifier.weight(1f)
) {
Text("Cancel", fontWeight = FontWeight.Medium)
}
Spacer(modifier = Modifier.width(8.dp))
TextButton(
onClick = {
scope.launch {
chatsViewModel.unblockUser(dialog.opponentKey)
dialogToUnblock = null
blocklistUpdateTrigger++
}
},
colors = ButtonDefaults.textButtonColors(
contentColor = Color(0xFF4CAF50)
),
modifier = Modifier.weight(1f)
) {
Text("Unblock", fontWeight = FontWeight.SemiBold)
}
}
}
},
confirmButton = {},
dismissButton = {},
containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
shape = RoundedCornerShape(16.dp)
)
@@ -1106,7 +1162,7 @@ fun SwipeableDialogItem(
}
// 2. КОНТЕНТ - поверх кнопок, сдвигается при свайпе
Box(
Column(
modifier = Modifier
.fillMaxSize()
.offset { IntOffset(animatedOffsetX.toInt(), 0) }
@@ -1132,23 +1188,30 @@ fun SwipeableDialogItem(
)
}
) {
DialogItem(
DialogItemContent(
dialog = dialog,
isDarkTheme = isDarkTheme,
isTyping = isTyping,
onClick = onClick
)
// Сепаратор внутри контента
val dividerColor = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE8E8E8)
Divider(
modifier = Modifier.padding(start = 84.dp),
color = dividerColor,
thickness = 0.5.dp
)
}
}
}
/** Элемент диалога из базы данных - ОПТИМИЗИРОВАННЫЙ */
/** Элемент диалога из базы данных - ОПТИМИЗИРОВАННЫЙ (без сепаратора для SwipeableDialogItem) */
@Composable
fun DialogItem(dialog: DialogUiModel, isDarkTheme: Boolean, isTyping: Boolean = false, onClick: () -> Unit) {
fun DialogItemContent(dialog: DialogUiModel, isDarkTheme: Boolean, isTyping: Boolean = false, onClick: () -> Unit) {
// 🔥 ОПТИМИЗАЦИЯ: Кешируем цвета и строки
val textColor = remember(isDarkTheme) { if (isDarkTheme) Color.White else Color.Black }
val secondaryTextColor = remember(isDarkTheme) { if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666) }
val dividerColor = remember(isDarkTheme) { if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE8E8E8) }
val avatarColors = remember(dialog.opponentKey, isDarkTheme) { getAvatarColor(dialog.opponentKey, isDarkTheme) }
val displayName = remember(dialog.opponentTitle, dialog.opponentKey) {
@@ -1166,24 +1229,23 @@ fun DialogItem(dialog: DialogUiModel, isDarkTheme: Boolean, isTyping: Boolean =
}
}
Column {
Row(
modifier =
Modifier.fillMaxWidth()
.clickable(onClick = onClick)
.padding(horizontal = 16.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
// Avatar container with online indicator
Box(modifier = Modifier.size(56.dp)) {
// Avatar
Box(
modifier =
Modifier.fillMaxSize()
.clip(CircleShape)
.background(avatarColors.backgroundColor),
contentAlignment = Alignment.Center
) {
Row(
modifier =
Modifier.fillMaxWidth()
.clickable(onClick = onClick)
.padding(horizontal = 16.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
// Avatar container with online indicator
Box(modifier = Modifier.size(56.dp)) {
// Avatar
Box(
modifier =
Modifier.fillMaxSize()
.clip(CircleShape)
.background(avatarColors.backgroundColor),
contentAlignment = Alignment.Center
) {
Text(
text = initials,
color = avatarColors.textColor,
@@ -1290,13 +1352,6 @@ fun DialogItem(dialog: DialogUiModel, isDarkTheme: Boolean, isTyping: Boolean =
}
}
}
Divider(
modifier = Modifier.padding(start = 84.dp),
color = dividerColor,
thickness = 0.5.dp
)
}
}
/**

View File

@@ -176,10 +176,19 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio
if (currentAccount.isEmpty()) return
try {
// Вычисляем правильный dialog_key (отсортированная комбинация ключей)
val dialogKey = if (currentAccount < opponentKey) {
"$currentAccount:$opponentKey"
} else {
"$opponentKey:$currentAccount"
}
android.util.Log.d("ChatsListViewModel", "Deleting dialog with key: $dialogKey")
// Удаляем все сообщения из диалога по dialog_key
database.messageDao().deleteDialog(
account = currentAccount,
dialogKey = opponentKey
dialogKey = dialogKey
)
// Также удаляем по from/to ключам (на всякий случай)
database.messageDao().deleteMessagesBetweenUsers(