From 9ecb38df242ad5e1dd4b52728168a3491c07d59d Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 25 Sep 2026 10:13:56 -0400 Subject: [PATCH] fix(cordn): name the attachment in the inbox row, and drop the bech32 above the QR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two things the Messages list and the group info page were showing that nobody could use. **A voice note read as an empty message.** The inbox row is built from `envelope.content`, and a message whose whole content is an attachment has none — so the row rendered "Dr. Edo Paz: " and trailed off, which looks like somebody sent nothing. It now names what was sent: Voice note, Photo, Video or File, chosen off the first attachment's MIME. The first one decides because a row is one line, and a message with a photo and a file in it is, to someone skimming an inbox, a message with a photo in it. A withdrawn message says so too, rather than falling through to the attachment label. **The share block printed the bech32 above the QR.** Three lines of characters that are not readable and not meant to be retyped, pushing the QR itself below the fold. Both things a person actually does with that string are still on the page — point a camera at the code, or press Copy link. Verified on the tablet: the row reads "Dr. Edo Paz: Voice note", and the share section is explainer, QR, Copy link. Co-Authored-By: Claude Opus 5 (1M context) --- .../chats/cordnGroup/CordnGroupInfoScreen.kt | 9 +++-- .../chats/rooms/ChatroomHeaderCompose.kt | 36 ++++++++++++++++++- .../composeResources/values/strings.xml | 5 +++ 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupInfoScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupInfoScreen.kt index df582650c4..d910c11426 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupInfoScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupInfoScreen.kt @@ -610,11 +610,10 @@ private fun ShareGroup( color = MaterialTheme.colorScheme.onSurfaceVariant, ) - SelectionContainer { - Text(ref, style = MaterialTheme.typography.bodySmall, modifier = Modifier.padding(vertical = 8.dp)) - } - - QrCodeDrawer(ref, Modifier.size(220.dp)) + // The bech32 itself is not shown. It is three lines of characters nobody + // reads, and both things a person actually does with it are already here: + // point a camera at the QR, or press Copy link. + QrCodeDrawer(ref, Modifier.padding(top = 8.dp).size(220.dp)) OutlinedButton( onClick = { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt index 0e7c2f5e3b..a9f4c393e2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt @@ -82,6 +82,11 @@ import com.vitorpamplona.amethyst.commons.resources.concord_server_label import com.vitorpamplona.amethyst.commons.resources.cordn_group import com.vitorpamplona.amethyst.commons.resources.cordn_group_no_messages_yet import com.vitorpamplona.amethyst.commons.resources.cordn_group_untitled +import com.vitorpamplona.amethyst.commons.resources.cordn_preview_deleted +import com.vitorpamplona.amethyst.commons.resources.cordn_preview_file +import com.vitorpamplona.amethyst.commons.resources.cordn_preview_photo +import com.vitorpamplona.amethyst.commons.resources.cordn_preview_video +import com.vitorpamplona.amethyst.commons.resources.cordn_preview_voice_note import com.vitorpamplona.amethyst.commons.resources.could_not_decrypt_the_message import com.vitorpamplona.amethyst.commons.resources.ephemeral_relay_chat import com.vitorpamplona.amethyst.commons.resources.geohash_chat @@ -146,8 +151,10 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayG import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.dal.ConcordServerRoomNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.dal.RelayGroupServerRoomNote import com.vitorpamplona.quartz.buzz.notifications.MemberAddedNotificationEvent +import com.vitorpamplona.quartz.cordn.appEncryptedMedia.CordnMediaTag import com.vitorpamplona.quartz.experimental.bitchat.geohash.GeohashChatEvent import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent +import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable @@ -545,6 +552,23 @@ private fun MarmotGroupRoomCompose( ) } +/** + * What to call a message whose whole content is an attachment. + * + * The first attachment decides, which is what the eye does too: a row is one + * line and a message with a photo and a file in it is, to a reader skimming the + * inbox, a message with a photo in it. + */ +private fun attachmentLabelFor(tags: TagArray): StringResource { + val first = CordnMediaTag.parseAll(tags).firstOrNull() ?: return Res.string.cordn_preview_file + return when { + first.isAudio -> Res.string.cordn_preview_voice_note + first.isImage -> Res.string.cordn_preview_photo + first.mimeType.startsWith("video/") -> Res.string.cordn_preview_video + else -> Res.string.cordn_preview_file + } +} + /** * One cordn room in the Messages list. * @@ -573,7 +597,17 @@ private fun CordnGroupRoomCompose( // inbox while the room shows the edit is the kind of mismatch that // reads as a sync bug. val text = annotations.contentOf(message.envelope.id) ?: message.envelope.content - "$authorName: ${text.take(200)}" + // A voice note or a photo carries no text, so the row used to read + // "Someone: " and trail off — an attachment looked like an empty + // message. Name what was sent instead, the way the bubble does. + val preview = + text.takeIf { it.isNotBlank() } + ?: if (annotations.isDeleted(message.envelope.id)) { + stringRes(Res.string.cordn_preview_deleted) + } else { + stringRes(attachmentLabelFor(message.envelope.tags)) + } + "$authorName: ${preview.take(200)}" } ?: stringRes(Res.string.cordn_group_no_messages_yet) ChannelName( diff --git a/commonsUI/src/commonMain/composeResources/values/strings.xml b/commonsUI/src/commonMain/composeResources/values/strings.xml index 11895c0511..9caa0142f3 100644 --- a/commonsUI/src/commonMain/composeResources/values/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values/strings.xml @@ -5381,6 +5381,11 @@ and the new-conversation picker. --> Group %1$s No messages yet + Message deleted + Voice note + Photo + Video + File cordn cordn group Encrypted group chat ordered by a coordinator you pick.