feat: Update dialog deletion logic to use sorted dialog keys for message removal
This commit is contained in:
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user