From f34268e4da1ffdc00241c4167336773cb56bb8d4 Mon Sep 17 00:00:00 2001 From: konstantiniiv Date: Wed, 3 Dec 2025 14:26:46 +0100 Subject: [PATCH 1/3] DROID-4057 empty title chat space --- .../main/java/com/anytypeio/anytype/ui/vault/VaultChatCard.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultChatCard.kt b/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultChatCard.kt index 574391721a..3fff25f1b6 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultChatCard.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultChatCard.kt @@ -181,7 +181,7 @@ fun VaultChatSpaceCard( modifier = Modifier .fillMaxWidth() .padding(start = 12.dp), - title = title, + title = title.ifEmpty { stringResource(id = R.string.untitled) }, subtitle = messageText ?: chatPreview?.message?.content?.text.orEmpty(), creatorName = creatorName, messageText = messageText, From 029ad73410e1a64789627f80ca5f815b53255fde Mon Sep 17 00:00:00 2001 From: konstantiniiv Date: Wed, 3 Dec 2025 14:53:45 +0100 Subject: [PATCH 2/3] DROID-4057 chat preview message history --- .../domain/chats/ChatPreviewContainer.kt | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/chats/ChatPreviewContainer.kt b/domain/src/main/java/com/anytypeio/anytype/domain/chats/ChatPreviewContainer.kt index 395c196afa..35bbf441b6 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/chats/ChatPreviewContainer.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/chats/ChatPreviewContainer.kt @@ -76,6 +76,9 @@ interface ChatPreviewContainer { private val previews = MutableStateFlow?>(null) private val attachmentIds = MutableStateFlow>>(emptyMap()) + // Buffer of last N preview messages per chat for fallback on deletion + private val messageHistory = ConcurrentHashMap>() + // Hot shared state for UI collectors @OptIn(ExperimentalCoroutinesApi::class) private val previewsState: StateFlow = previews @@ -115,6 +118,7 @@ interface ChatPreviewContainer { attachmentIds.value = emptyMap() // Reset attachment tracking previews.value = null // Reset previews + messageHistory.clear() // Reset message history val initial = runCatching { repo.subscribeToMessagePreviews(SUBSCRIPTION_ID) @@ -122,6 +126,14 @@ interface ChatPreviewContainer { logger.logWarning("Error while getting initial previews: ${it.message}") }.getOrDefault(emptyList()) + // Initialize history from initial previews + initial.forEach { preview -> + preview.message?.let { message -> + val history = messageHistory.getOrPut(preview.chat) { ArrayDeque(MAX_MESSAGE_HISTORY) } + history.addLast(message) + } + } + previews.value = initial // ← Ready (may be empty) trackMissingAttachments(initial) collectEvents(initial) @@ -133,6 +145,7 @@ interface ChatPreviewContainer { job?.cancel() job = null previews.value = null // back to Loading for next start() + messageHistory.clear() // clear message history unsubscribeAll() attachmentFlows.clear() // let the cached StateFlows be GC-ed } @@ -200,7 +213,11 @@ interface ChatPreviewContainer { is Event.Command.Chats.Delete -> state.map { preview -> if (preview.chat == event.context && preview.message?.id == event.message) { - preview.copy(message = null) + // Remove deleted message from history and get previous message + val history = messageHistory[event.context] + history?.removeIf { it.id == event.message } + val previousMessage = history?.lastOrNull() + preview.copy(message = previousMessage) } else preview } @@ -214,6 +231,14 @@ interface ChatPreviewContainer { state: List, event: Event.Command.Chats.Add ): List { + // Store message in history buffer for fallback on deletion + val chatId = event.context + val history = messageHistory.getOrPut(chatId) { ArrayDeque(MAX_MESSAGE_HISTORY) } + if (history.size >= MAX_MESSAGE_HISTORY) { + history.removeFirst() + } + history.addLast(event.message) + // Extract attachment IDs val messageAttachmentIds = event.message.attachments.map { it.target }.toSet() val dependencyIds = event.dependencies.map { it.id }.toSet() @@ -359,6 +384,7 @@ interface ChatPreviewContainer { companion object { private const val SUBSCRIPTION_ID = "chat-previews-subscription" private const val ATTACHMENT_SUBSCRIPTION_POSTFIX = "chat-previews-attachments" + private const val MAX_MESSAGE_HISTORY = 10 } } } \ No newline at end of file From cab640c2ba3cab3c84b075aadb9a7d0d9f7449b3 Mon Sep 17 00:00:00 2001 From: konstantiniiv Date: Wed, 3 Dec 2025 15:25:04 +0100 Subject: [PATCH 3/3] DROID-4057 fix --- .../anytype/domain/chats/ChatPreviewContainer.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/chats/ChatPreviewContainer.kt b/domain/src/main/java/com/anytypeio/anytype/domain/chats/ChatPreviewContainer.kt index 35bbf441b6..7c395ca76b 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/chats/ChatPreviewContainer.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/chats/ChatPreviewContainer.kt @@ -12,6 +12,7 @@ import com.anytypeio.anytype.domain.debugging.Logger import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.ConcurrentLinkedDeque import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -76,8 +77,8 @@ interface ChatPreviewContainer { private val previews = MutableStateFlow?>(null) private val attachmentIds = MutableStateFlow>>(emptyMap()) - // Buffer of last N preview messages per chat for fallback on deletion - private val messageHistory = ConcurrentHashMap>() + // Buffer of last N preview messages per chat for fallback on deletion (thread-safe) + private val messageHistory = ConcurrentHashMap>() // Hot shared state for UI collectors @OptIn(ExperimentalCoroutinesApi::class) @@ -129,7 +130,7 @@ interface ChatPreviewContainer { // Initialize history from initial previews initial.forEach { preview -> preview.message?.let { message -> - val history = messageHistory.getOrPut(preview.chat) { ArrayDeque(MAX_MESSAGE_HISTORY) } + val history = messageHistory.getOrPut(preview.chat) { ConcurrentLinkedDeque() } history.addLast(message) } } @@ -233,7 +234,7 @@ interface ChatPreviewContainer { ): List { // Store message in history buffer for fallback on deletion val chatId = event.context - val history = messageHistory.getOrPut(chatId) { ArrayDeque(MAX_MESSAGE_HISTORY) } + val history = messageHistory.getOrPut(chatId) { ConcurrentLinkedDeque() } if (history.size >= MAX_MESSAGE_HISTORY) { history.removeFirst() }