Правки
This commit is contained in:
@@ -149,31 +149,44 @@ fun ChatDetailScreen(
|
||||
viewModel.setChatId(chatId)
|
||||
}
|
||||
|
||||
|
||||
// Безопасная группировка сообщений с обработкой ошибок
|
||||
val listItems = remember(state.messages) {
|
||||
val items = mutableListOf<MessageListItem>()
|
||||
if (state.messages.isEmpty()) return@remember items
|
||||
|
||||
// Группируем от старых к новым (для normal layout)
|
||||
val reversedMessages = state.messages.reversed()
|
||||
var i = 0
|
||||
while (i < reversedMessages.size) {
|
||||
val isoDate = reversedMessages[i].createdAt
|
||||
val localDate = viewModel.getLocalDateString(isoDate)
|
||||
val dayMessages = mutableListOf<chats.domain.model.Message>()
|
||||
|
||||
while (i < reversedMessages.size && viewModel.getLocalDateString(reversedMessages[i].createdAt) == localDate) {
|
||||
dayMessages.add(reversedMessages[i])
|
||||
i++
|
||||
}
|
||||
|
||||
// Добавляем заголовок даты
|
||||
items.add(MessageListItem.DateHeader(viewModel.formatDateHeader(isoDate)))
|
||||
|
||||
// Добавляем сообщения
|
||||
dayMessages.forEach { msg ->
|
||||
items.add(MessageListItem.MessageItem(msg))
|
||||
try {
|
||||
// Удаляем дубликаты по ID сообщения
|
||||
val uniqueMessages = state.messages.distinctBy { it.id }
|
||||
if (uniqueMessages.isEmpty()) return@remember items
|
||||
|
||||
// Группируем от старых к новым (для normal layout)
|
||||
val reversedMessages = uniqueMessages.reversed()
|
||||
var i = 0
|
||||
while (i < reversedMessages.size) {
|
||||
val isoDate = reversedMessages[i].createdAt
|
||||
val localDate = viewModel.getLocalDateString(isoDate)
|
||||
val dayMessages = mutableListOf<chats.domain.model.Message>()
|
||||
|
||||
while (i < reversedMessages.size && viewModel.getLocalDateString(reversedMessages[i].createdAt) == localDate) {
|
||||
dayMessages.add(reversedMessages[i])
|
||||
i++
|
||||
}
|
||||
|
||||
// Добавляем заголовок даты
|
||||
val safeDateHeader = try {
|
||||
viewModel.formatDateHeader(isoDate)
|
||||
} catch (e: Exception) {
|
||||
isoDate.take(10)
|
||||
}
|
||||
items.add(MessageListItem.DateHeader(safeDateHeader))
|
||||
|
||||
// Добавляем сообщения
|
||||
dayMessages.forEach { msg ->
|
||||
items.add(MessageListItem.MessageItem(msg))
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.e("ChatDetailScreen", "Error building listItems", e)
|
||||
}
|
||||
items
|
||||
}
|
||||
@@ -255,28 +268,38 @@ fun ChatDetailScreen(
|
||||
}
|
||||
|
||||
// Авто-скролл к новым сообщениям - только если мы уже внизу
|
||||
val lastMessageId = state.messages.lastOrNull()?.id
|
||||
// Берём firstOrNull, т.к. messages отсортированы по sequenceId убыванию (новые в начале)
|
||||
val lastMessageId = state.messages.firstOrNull()?.id
|
||||
LaunchedEffect(lastMessageId) {
|
||||
if (lastMessageId != null && listItems.isNotEmpty()) {
|
||||
val isAtBottom = listState.layoutInfo.run {
|
||||
val visibleItems = visibleItemsInfo
|
||||
val totalCount = totalItemsCount
|
||||
if (totalCount == 0 || visibleItems.isEmpty()) return@run true
|
||||
visibleItems.last().index >= totalCount - 2
|
||||
}
|
||||
|
||||
if (isAtBottom) {
|
||||
listState.animateScrollToItem(listItems.size - 1)
|
||||
// Даём время LazyColumn отрисовать новое сообщение и обновить layout
|
||||
delay(200)
|
||||
val layoutInfo = listState.layoutInfo
|
||||
val visibleItems = layoutInfo.visibleItemsInfo
|
||||
val totalCount = layoutInfo.totalItemsCount
|
||||
if (totalCount > 0 && visibleItems.isNotEmpty()) {
|
||||
val lastVisibleIndex = visibleItems.last().index
|
||||
val atBottom = lastVisibleIndex >= totalCount - 2
|
||||
android.util.Log.d("ChatDetailScreen", "Auto-scroll check: lastVisible=$lastVisibleIndex, total=$totalCount, atBottom=$atBottom, msgId=$lastMessageId")
|
||||
if (atBottom) {
|
||||
listState.animateScrollToItem(listItems.size - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Автоматическая прокрутка при инициализации
|
||||
// Автоматическая прокрутка при инициализации - только один раз
|
||||
var initialScrollDone by remember { mutableStateOf(false) }
|
||||
LaunchedEffect(listItems.size) {
|
||||
if (listItems.isNotEmpty()) {
|
||||
listState.scrollToItem(listItems.size - 1)
|
||||
viewModel.onInitialScrollDone()
|
||||
viewModel.markAsRead()
|
||||
if (!initialScrollDone && listItems.isNotEmpty() && listItems.size > 1) {
|
||||
try {
|
||||
listState.scrollToItem(listItems.size - 1)
|
||||
initialScrollDone = true
|
||||
viewModel.onInitialScrollDone()
|
||||
viewModel.markAsRead()
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.e("ChatDetailScreen", "Error in auto-scroll", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,6 +323,20 @@ fun ChatDetailScreen(
|
||||
state.messages.count { !it.isRead && it.senderId != viewModel.getCurrentUserId() }
|
||||
}
|
||||
|
||||
// Авто-прочитка при открытии чата - если мы внизу
|
||||
LaunchedEffect(Unit) {
|
||||
delay(500)
|
||||
val layoutInfo = listState.layoutInfo
|
||||
val visibleItems = layoutInfo.visibleItemsInfo
|
||||
val totalCount = layoutInfo.totalItemsCount
|
||||
if (totalCount > 0 && visibleItems.isNotEmpty()) {
|
||||
val lastVisibleIndex = visibleItems.last().index
|
||||
if (lastVisibleIndex >= totalCount - 2) {
|
||||
viewModel.markAsRead()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Авто-прочитка при нахождении внизу списка
|
||||
LaunchedEffect(listState.isScrollInProgress) {
|
||||
if (!listState.isScrollInProgress) {
|
||||
|
||||
Reference in New Issue
Block a user