From eb3b7077fd59488ad03f8c35230906f7a6afc972 Mon Sep 17 00:00:00 2001 From: The Daniel Date: Sat, 28 Feb 2026 18:53:32 -0500 Subject: [PATCH] feat: show "Replying to" label in quoted notes Follow-up to #1723. When a quoted note is itself a reply, display a compact "Replying to [username]" label above the content instead of showing nothing. Uses the event's p-tags to resolve reply targets directly, matching the Damus-style display. --- .../amethyst/ui/components/RichTextViewer.kt | 2 ++ .../amethyst/ui/note/ReplyInformation.kt | 25 +++++++++++++++++++ .../amethyst/ui/note/types/Text.kt | 15 +++++++++++ 3 files changed, 42 insertions(+) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt index 73aa212b6..7870428f5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt @@ -595,6 +595,7 @@ fun DisplayFullNote( baseNote = note, modifier = MaterialTheme.colorScheme.innerPostModifier, isQuotedNote = true, + unPackReply = false, quotesLeft = quotesLeft - 1, parentBackgroundColor = backgroundColor, accountViewModel = accountViewModel, @@ -867,6 +868,7 @@ private fun DisplayNoteFromTag( baseNote = baseNote, modifier = MaterialTheme.colorScheme.innerPostModifier, isQuotedNote = true, + unPackReply = false, quotesLeft = quotesLeft - 1, parentBackgroundColor = backgroundColor, accountViewModel = accountViewModel, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt index 5dd151792..1a50d6e23 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt @@ -116,6 +116,31 @@ fun ReplyInformationChannel( } } +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun ReplyToLabel( + replyingDirectlyTo: Note, + accountViewModel: AccountViewModel, + nav: INav, +) { + val user = replyingDirectlyTo.author ?: return + + FlowRow { + Text( + stringRes(id = R.string.replying_to), + fontSize = 13.sp, + color = MaterialTheme.colorScheme.placeholderText, + ) + + ReplyInfoMention( + user = user, + prefix = "", + accountViewModel = accountViewModel, + onUserTagClick = { nav.nav(routeFor(it)) }, + ) + } +} + @Composable private fun ReplyInfoMention( user: User, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt index fc3a43e49..4103576bc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt @@ -42,6 +42,7 @@ import com.vitorpamplona.amethyst.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContent +import com.vitorpamplona.amethyst.ui.note.ReplyInformationChannel import com.vitorpamplona.amethyst.ui.note.ReplyNoteComposition import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -49,10 +50,13 @@ import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nip01Core.tags.people.hasAnyTaggedUser +import com.vitorpamplona.quartz.nip01Core.tags.people.taggedUsers import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip14Subject.subject import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList @Composable fun RenderTextEvent( @@ -98,6 +102,17 @@ fun RenderTextEvent( ReplyNoteComposition(replyingDirectlyTo, backgroundColor, accountViewModel, nav) Spacer(modifier = StdVertSpacer) } + } else if (!unPackReply && !makeItShort && noteEvent is BaseThreadedEvent && noteEvent.hasAnyTaggedUser()) { + val mentions = + remember(noteEvent) { + noteEvent.taggedUsers().map { it.pubKey }.toImmutableList() + } + ReplyInformationChannel( + replyTo = persistentListOf(note), + mentions = mentions, + accountViewModel = accountViewModel, + nav = nav, + ) } // Check if this is an audio-only event (content is just an audio URL with waveform IMeta)