diff --git a/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactListViewModel.kt b/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactListViewModel.kt
index a7769fe4a7d25a89579a01c76844b4215dc8d82b..d4dc6985533b468657f8ae243cad406f22766a8a 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactListViewModel.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/ContactListViewModel.kt
@@ -57,9 +57,10 @@ constructor(
     override fun updateFilteredList() {
         super.updateFilteredList()
 
-        _selectedContactId.value?.let { id ->
-            if (!contactList.map { it.contact.id }.contains(id))
-                _selectedContactId.value = null
+        // reset selected contact to null if not available after filtering
+        val id = _selectedContactId.value
+        if (id != null && !contactList.map { it.contact.id }.contains(id)) {
+            _selectedContactId.value = null
         }
     }
 
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationViewModel.kt b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationViewModel.kt
index 8d9902e240f3f07a51a1c550a185055f42704e25..3f4d92305fb1b8ffd1a41f3108dd9b23a47a64f3 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationViewModel.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationViewModel.kt
@@ -85,6 +85,9 @@ constructor(
             val text = _newMessage.value
             _newMessage.value = ""
 
+            // don't send empty or blank messages
+            if (text.isBlank()) return
+
             val start = LogUtils.now()
             val m = createMessage(text)
             messagingManager.addLocalMessage(m)
@@ -125,18 +128,20 @@ constructor(
         try {
             val start = LogUtils.now()
             val headers = conversationManager.getMessageHeaders(_contactId.value!!)
-            LogUtils.logDuration(LOG, "Loading messages", start)
+            LogUtils.logDuration(LOG, "Loading message headers", start)
             // Sort headers by timestamp in *descending* order
             val sorted = headers.sortedByDescending { it.timestamp }
             _messages.apply {
                 clear()
+                val start = LogUtils.now()
                 addAll(
                     // todo: use ConversationVisitor to also display Request and Notice Messages
                     sorted.filterIsInstance<PrivateMessageHeader>().map(::messageHeaderToItem)
                 )
+                LogUtils.logDuration(LOG, "Loading messages", start)
             }
         } catch (e: NoSuchContactException) {
-            // finishOnUiThread()
+            LogUtils.logException(LOG, Level.WARNING, e)
         } catch (e: DbException) {
             LogUtils.logException(LOG, Level.WARNING, e)
         }
@@ -147,17 +152,15 @@ constructor(
         val item = ConversationMessageItem(h)
         if (h.hasText()) {
             item.text = loadMessageText(h.id)
+        } else {
+            LOG.warning { "private message without text" }
         }
         return item
     }
 
     private fun loadMessageText(m: MessageId): String? {
         try {
-            val start = LogUtils.now()
-            val text = messagingManager.getMessageText(m)
-            LogUtils.logDuration(LOG, "Loading text", start)
-
-            return text
+            return messagingManager.getMessageText(m)
         } catch (e: DbException) {
             LogUtils.logException(LOG, Level.WARNING, e)
         }
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageView.kt b/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageView.kt
index 2ce3ccbbde31424da9bec60638c4a965428811bf..655237c74c32986887dda65b241a95b822a5ad6a 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageView.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/conversation/PrivateMessageView.kt
@@ -24,13 +24,12 @@ fun PrivateMessageView(
         ContactList(contactListViewModel, addContactViewModel)
         VerticalDivider()
         Column(modifier = Modifier.weight(1f).fillMaxHeight()) {
-            contactListViewModel.selectedContactId.value?.also { contactId ->
-                Conversation(
-                    contactId,
-                    conversationViewModel,
-                    introductionViewModel
-                )
-            } ?: UiPlaceholder()
+            val id = contactListViewModel.selectedContactId.value
+            if (id != null) {
+                Conversation(id, conversationViewModel, introductionViewModel)
+            } else {
+                UiPlaceholder()
+            }
         }
     }
 }
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/conversation/TextBubble.kt b/src/main/kotlin/org/briarproject/briar/desktop/conversation/TextBubble.kt
index 33f8a365d44d1cedd724d926bc9eb30405deebad..63fc4c7f177b26799dd00baf65322f7e41be3938 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/conversation/TextBubble.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/conversation/TextBubble.kt
@@ -44,7 +44,9 @@ fun TextBubble(m: ConversationMessageItem) {
                         if (!m.isIncoming) {
                             val modifier = Modifier.size(12.dp).align(Alignment.CenterVertically)
                             val icon =
-                                if (m.isSeen) Icons.Filled.DoneAll else if (m.isSent) Icons.Filled.Done else Icons.Filled.Schedule
+                                if (m.isSeen) Icons.Filled.DoneAll // acknowledged
+                                else if (m.isSent) Icons.Filled.Done // sent
+                                else Icons.Filled.Schedule // waiting
                             Icon(icon, "sent", modifier)
                         }
                     }