From 7bb46d2b740c1fcdcc0b8f96895ad841ecaafab8 Mon Sep 17 00:00:00 2001 From: Kgothatso Ngako Date: Mon, 27 Apr 2026 02:37:06 +0200 Subject: [PATCH] Quote a nostrEvent --- .../compose/database/model/NostrEvent.kt | 10 +++++ .../repository/DatabaseNostrRepository.kt | 40 ++++++++++++++----- .../ui/composable/NostrEventDetailScreen.kt | 9 +++-- .../ui/composable/WriteNewNoteScreen.kt | 33 +++++++++++++-- .../ui/composable/navigation/AuxNavHost.kt | 7 ++++ .../widgets/detail/TextNoteEventDetail.kt | 10 +++-- .../ui/view/model/WriteNewNoteViewModel.kt | 9 ++++- 7 files changed, 97 insertions(+), 21 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/NostrEvent.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/NostrEvent.kt index 9cdc14a8..5e0ad92c 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/NostrEvent.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/NostrEvent.kt @@ -277,6 +277,16 @@ data class NostrEvent( } } + fun toTextNoteEvent(): TextNoteEvent { + return TextNoteEvent( + id = id, + content = content, + sig = sig, + tags = tags, + createdAt = createdAt.epochSeconds, + pubKey = pubKey + ) + } companion object { fun fromEvent(event: Event, synchronizeNostrEventRequest: SynchronizeNostrEventRequest? = null): NostrEvent? = try { diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/repository/DatabaseNostrRepository.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/repository/DatabaseNostrRepository.kt index 890ad8ee..7d8cf6f7 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/repository/DatabaseNostrRepository.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/repository/DatabaseNostrRepository.kt @@ -46,6 +46,7 @@ import com.vitorpamplona.quartz.nip10Notes.tags.prepareETagsAsReplyTo import com.vitorpamplona.quartz.nip17Dm.settings.ChatMessageRelayListEvent import com.vitorpamplona.quartz.nip18Reposts.RepostEvent import com.vitorpamplona.quartz.nip18Reposts.quotes.quotes +import com.vitorpamplona.quartz.nip21UriScheme.toNostrUri import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent import com.vitorpamplona.quartz.nip28PublicChat.list.ChannelListEvent import com.vitorpamplona.quartz.nip31Alts.AltTag @@ -232,25 +233,28 @@ class DatabaseNostrRepository( override suspend fun createNewTextNote( publicKey: HexKey, - text: String, + textInput: String, inReplyToNostrEvent: LocalNostrEvent?, quotedNostrEvent: LocalNostrEvent?, onError: () -> Unit, onSuccess: () -> Unit ) { - // TODO: Handle event and profile tags... + val quotedNostrURI = quotedNostrEvent?.let { + // TODO: Convert qoutedNostrEvent to nostrURI + val quotedTextNoteEvent = it.nostrEvent.toTextNoteEvent() + + val relayHint = null // TODO: get relyhint from where ever the nostrEvent was synced from... + + "\n\n${quotedTextNoteEvent.toNostrUri(relayHint)}" + } ?: "" + val text: String = textInput + quotedNostrURI + + // TODO: Handle mentioned profile tags... val textNote = TextNoteEvent.build( note = text, ) { inReplyToNostrEvent?.let { - val replyToTextNoteEvent = TextNoteEvent( - id = it.nostrEvent.id, - content = it.nostrEvent.content, - sig = it.nostrEvent.sig, - tags = it.nostrEvent.tags, - createdAt = it.nostrEvent.createdAt.epochSeconds, - pubKey = it.nostrEvent.pubKey - ) + val replyToTextNoteEvent = it.nostrEvent.toTextNoteEvent() val replyingTo = EventHintBundle( replyToTextNoteEvent @@ -277,6 +281,22 @@ class DatabaseNostrRepository( } } + quotedNostrEvent?.let { + it.profile?.let { profile -> + val ptags = arrayOf( + profile, + // Other profiles tagged in the event... + ).map { notifyProfile -> + PTag( + notifyProfile.publicKey, + // TODO: Add relayHints... + ) + } + + notify(ptags) + } + } + hashtags(findHashtags(text)) references(findURLs(text)) quotes(findNostrUris(text)) diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/NostrEventDetailScreen.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/NostrEventDetailScreen.kt index edaf4c13..f0fc1867 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/NostrEventDetailScreen.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/NostrEventDetailScreen.kt @@ -40,7 +40,8 @@ fun NostrEventDetailScreen( onNavigateBack: () -> Unit, onNavigateToEvent: (Route) -> Unit, onNavigateToEditProfile: () -> Unit, - onNavigateToWriteAReply: (String) -> Unit + onNavigateToWriteAReply: (String) -> Unit, + onNavigateToQuoteNostrEvent: (String) -> Unit, ) { val nostrEventDetailViewModel: NostrEventDetailViewModel = viewModel( factory = NostrEventDetailViewModel.factory( @@ -76,7 +77,8 @@ fun NostrEventDetailScreen( TextNoteEventDetail( feedListUIState.localNostrEvent, onNavigateBack = onNavigateBack, - onNavigateToWriteAReply = onNavigateToWriteAReply + onNavigateToWriteAReply = onNavigateToWriteAReply, + onNavigateToQuoteNostrEvent = onNavigateToQuoteNostrEvent ) } RepostEvent.KIND -> { @@ -163,7 +165,8 @@ It has survived not only five centuries, but also the leap into electronic types onNavigateBack = {}, onNavigateToEvent = {}, onNavigateToWriteAReply = {}, - onNavigateToEditProfile = {} + onNavigateToEditProfile = {}, + onNavigateToQuoteNostrEvent = {} ) } } diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/WriteNewNoteScreen.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/WriteNewNoteScreen.kt index e02960a1..1e843243 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/WriteNewNoteScreen.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/WriteNewNoteScreen.kt @@ -125,6 +125,7 @@ fun WriteNewNoteScreen( color = MaterialTheme.colorScheme.onSurfaceVariant ) } + TextField( modifier = Modifier.fillMaxWidth(), value = writeNewNoteViewModel.writeNewNoteFormState.textField.text.value, @@ -147,7 +148,13 @@ fun WriteNewNoteScreen( ), label = { Text( - text = "What vibrations do you want to send out?", + text = if (writeNewNoteUIState.inReplyToNostrEvent != null) { + "What's your reply to the above" + } else if (writeNewNoteUIState.quotedNostrEvent != null) { + "What's your comment on the below" + } else { + "What vibrations do you want to send out?" + }, maxLines = 1, ) }, @@ -164,6 +171,17 @@ fun WriteNewNoteScreen( ) } ) + + if (writeNewNoteUIState.quotedNostrEvent?.nostrEvent?.kind == TextNoteEvent.KIND) { + Card( + modifier = Modifier.padding( + start = 50.dp, + top = 10.dp + ) + ) { + writeNewNoteUIState.quotedNostrEvent.RenderNotePreview() + } + } } @@ -260,6 +278,13 @@ fun WriteNewNoteScreen( textAlign = TextAlign.Center ) + if (writeNewNoteUIState.quotedNostrEvent?.nostrEvent?.kind == TextNoteEvent.KIND) { + Card { + writeNewNoteUIState.quotedNostrEvent.RenderNotePreview() + } + + } + Text( text = Clock.System.now().toFormattedTimeAndDateString(), style = MaterialTheme.typography.labelSmall @@ -335,9 +360,9 @@ private fun WriteNewNoteScreenPreview() { replyToNostrEventId = null, quotedNostrEventId = null, initialWriteNewNoteUIState = - WriteNewNoteUIState.ConfirmNote( - text = "Yes, I did it. So WHAT?!", - inReplyToNostrEvent = LocalNostrEvent( + WriteNewNoteUIState.InputPrompt( +// text = "Yes, I did it. So WHAT?!", + quotedNostrEvent = LocalNostrEvent( nostrEvent = NostrEvent( id = "eventId", pubKey = "publicKey", diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/navigation/AuxNavHost.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/navigation/AuxNavHost.kt index 63e8f30f..e9e86b37 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/navigation/AuxNavHost.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/navigation/AuxNavHost.kt @@ -392,6 +392,13 @@ fun AuxNavHost( navController.navigate( route = ImplementationPendingRoute("Edit Profile") ) + }, + onNavigateToQuoteNostrEvent = { nostrEventId -> + navController.navigate( + route = WriteNewNoteRoute( + quotedEventId = nostrEventId + ) + ) } ) } diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/widgets/detail/TextNoteEventDetail.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/widgets/detail/TextNoteEventDetail.kt index f28a5d9c..af1c9c2e 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/widgets/detail/TextNoteEventDetail.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/widgets/detail/TextNoteEventDetail.kt @@ -49,7 +49,8 @@ import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent fun TextNoteEventDetail( localNostrEvent: LocalNostrEvent, onNavigateBack: () -> Unit, - onNavigateToWriteAReply: (String) -> Unit + onNavigateToWriteAReply: (String) -> Unit, + onNavigateToQuoteNostrEvent: (String) -> Unit, ) { Scaffold( modifier = Modifier.fillMaxSize(), @@ -184,7 +185,9 @@ fun TextNoteEventDetail( IconButton( onClick = { - // TODO: Repost... + onNavigateToQuoteNostrEvent.invoke( + localNostrEvent.nostrEvent.id + ) } ) { Icon( @@ -253,7 +256,8 @@ It has survived not only five centuries, but also the leap into electronic types ) ), onNavigateBack = {}, - onNavigateToWriteAReply = {} + onNavigateToWriteAReply = {}, + onNavigateToQuoteNostrEvent = {} ) } } diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/WriteNewNoteViewModel.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/WriteNewNoteViewModel.kt index 7a621e5f..17ea3a8f 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/WriteNewNoteViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/WriteNewNoteViewModel.kt @@ -71,6 +71,12 @@ class WriteNewNoteViewModel( ).firstOrNull() } + val nostrEventBeingQuoted = quotedNostrEventId?.let { + nostrRepository.observeLocalNostrEventById( + it + ).firstOrNull() + } + val activePublicKey = SeedManager.activePublicKey().toHexKey() // TODO: Get note being replied too... @@ -82,7 +88,8 @@ class WriteNewNoteViewModel( writeNewNoteUIState = if (profileWithFollowing != null) { WriteNewNoteUIState.InputPrompt( localProfile = profileWithFollowing, - inReplyToNostrEvent = nostrEventBeingRepliedTo + inReplyToNostrEvent = nostrEventBeingRepliedTo, + quotedNostrEvent = nostrEventBeingQuoted ) } else { WriteNewNoteUIState.Error