diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 3f657b2bd..a74b41df1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -529,13 +529,12 @@ class Account( if (!signer.isWriteable()) return null if (note.hasReacted(userProfile(), reaction)) return null - val noteEvent = note.event ?: return null + val eventHint = note.toEventHint() ?: return null // For NIP-17 private groups, we don't support tracked mode (too complex) - if (noteEvent is NIP17Group) return null + if (eventHint.event is NIP17Group) return null - val relayHint = note.relays.firstOrNull()?.url - val event = ReactionAction.reactTo(noteEvent, reaction, signer, relayHint) + val event = ReactionAction.reactTo(eventHint, reaction, signer) val relays = computeRelayListToBroadcast(event) return event to relays @@ -1360,19 +1359,15 @@ class Account( } suspend fun createInteractiveStoryReadingState( - root: InteractiveStoryBaseEvent, - rootRelay: NormalizedRelayUrl?, - readingScene: InteractiveStoryBaseEvent, - readingSceneRelay: NormalizedRelayUrl?, + root: EventHintBundle, + readingScene: EventHintBundle, ) { if (!isWriteable()) return val template = InteractiveStoryReadingStateEvent.build( root = root, - rootRelay = rootRelay, currentScene = readingScene, - currentSceneRelay = readingSceneRelay, ) val event = signer.sign(template) @@ -1391,8 +1386,7 @@ class Account( suspend fun updateInteractiveStoryReadingState( readingState: InteractiveStoryReadingStateEvent, - readingScene: InteractiveStoryBaseEvent, - readingSceneRelay: NormalizedRelayUrl?, + readingScene: EventHintBundle, ) { if (!isWriteable()) return @@ -1400,7 +1394,6 @@ class Account( InteractiveStoryReadingStateEvent.update( base = readingState, currentScene = readingScene, - currentSceneRelay = readingSceneRelay, ) val event = signer.sign(template) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt index 531c0a3dd..75df5628b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -61,7 +61,6 @@ import com.vitorpamplona.quartz.experimental.trustedAssertions.list.TrustProvide import com.vitorpamplona.quartz.experimental.zapPolls.PollNoteEvent import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent -import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.isAddressable @@ -420,18 +419,18 @@ object LocalCache : ILocalCache, ICacheProvider { return null } - override fun checkGetOrCreateNote(key: String): Note? { - if (ATag.isATag(key)) { - return checkGetOrCreateAddressableNote(key) + override fun checkGetOrCreateNote(hexKey: String): Note? { + if (ATag.isATag(hexKey)) { + return checkGetOrCreateAddressableNote(hexKey) } - if (isValidHex(key)) { - val note = getOrCreateNote(key) + if (isValidHex(hexKey)) { + val note = getOrCreateNote(hexKey) val noteEvent = note.event return if (noteEvent is AddressableEvent) { // upgrade to the latest - val newNote = checkGetOrCreateAddressableNote(noteEvent.aTag().toTag()) + val newNote = getOrCreateAddressableNote(noteEvent.address()) - if (newNote != null && newNote.event == null) { + if (newNote.event == null) { val author = note.author ?: getOrCreateUser(noteEvent.pubKey) newNote.loadEvent(noteEvent as Event, author, emptyList()) note.moveAllReferencesTo(newNote) @@ -1407,10 +1406,13 @@ object LocalCache : ILocalCache, ICacheProvider { ) = consumeBaseReplaceable(event, relay, wasVerified) private fun consumeBaseReplaceable( - event: BaseAddressableEvent, + event: Event, relay: NormalizedRelayUrl?, wasVerified: Boolean, ): Boolean { + // TODO: Redo the Event sctructure in Quartz to avoid this check + check(event is AddressableEvent) { "Event must be addressable: ${event.kind}" } + val version = getOrCreateNote(event.id) val replaceableNote = getOrCreateAddressableNote(event.address()) val author = getOrCreateUser(event.pubKey) @@ -2767,7 +2769,7 @@ object LocalCache : ILocalCache, ICacheProvider { note?.event?.let { noteEvent -> if (noteEvent is AddressableEvent) { - getAddressableNoteIfExists(noteEvent.aTag().toTag())?.addRelay(relay) + getAddressableNoteIfExists(noteEvent.address())?.addRelay(relay) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt index b85ba7c87..25bdca7df 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt @@ -143,7 +143,7 @@ fun routeForInner( } is AddressableEvent -> { - Route.Note(noteEvent.aTag().toTag()) + Route.Note(noteEvent.addressTag()) } else -> { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt index 58d55e338..71e7ba8a8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt @@ -61,12 +61,13 @@ fun RenderInteractiveStory( accountViewModel: AccountViewModel, nav: INav, ) { - val baseRootEvent = baseNote.event as? InteractiveStoryBaseEvent ?: return + val baseRootEvent = baseNote.toEventHint() ?: return val address = baseNote.address() ?: return // keep updating the root event with new versions val note = observeNote(baseNote, accountViewModel) - val rootEvent = note.value?.note?.event as? InteractiveStoryBaseEvent ?: return + val rootHint = note.value.note.toEventHint() ?: return + val rootEvent = rootHint.event // keep updating the reading state event with new versions val readingStateNote = accountViewModel.getInteractiveStoryReadingState(address.toValue()) @@ -83,11 +84,11 @@ fun RenderInteractiveStory( RenderInteractiveStory( section = it, onSelect = { - val event = it.event as? InteractiveStoryBaseEvent ?: return@RenderInteractiveStory - accountViewModel.updateInteractiveStoryReadingState(baseRootEvent, event) + val eventHint = it.toEventHint() ?: return@RenderInteractiveStory + accountViewModel.updateInteractiveStoryReadingState(baseRootEvent, eventHint) }, onRestart = { - accountViewModel.updateInteractiveStoryReadingState(baseRootEvent, rootEvent) + accountViewModel.updateInteractiveStoryReadingState(baseRootEvent, rootHint) }, makeItShort = makeItShort, canPreview = canPreview, @@ -103,11 +104,11 @@ fun RenderInteractiveStory( RenderInteractiveStory( section = rootEvent, onSelect = { - val event = it.event as? InteractiveStoryBaseEvent ?: return@RenderInteractiveStory - accountViewModel.updateInteractiveStoryReadingState(baseRootEvent, event) + val eventHint = it.toEventHint() ?: return@RenderInteractiveStory + accountViewModel.updateInteractiveStoryReadingState(baseRootEvent, eventHint) }, onRestart = { - accountViewModel.updateInteractiveStoryReadingState(baseRootEvent, rootEvent) + accountViewModel.updateInteractiveStoryReadingState(baseRootEvent, rootHint) }, makeItShort = makeItShort, canPreview = canPreview, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index c1c2eca36..647a4f905 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -91,6 +91,7 @@ import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair +import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.relay.client.EmptyNostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.RelayOfflineTracker import com.vitorpamplona.quartz.nip01Core.relay.client.auth.EmptyIAuthStatus @@ -1480,21 +1481,17 @@ class AccountViewModel( fun getInteractiveStoryReadingState(dATag: String): AddressableNote = LocalCache.getOrCreateAddressableNote(InteractiveStoryReadingStateEvent.createAddress(account.signer.pubKey, dATag)) fun updateInteractiveStoryReadingState( - root: InteractiveStoryBaseEvent, - readingScene: InteractiveStoryBaseEvent, + rootHint: EventHintBundle, + readingSceneHint: EventHintBundle, ) { launchSigner { - val sceneNoteRelayHint = LocalCache.getOrCreateAddressableNote(readingScene.address()).relayHintUrl() - - val readingState = getInteractiveStoryReadingState(root.addressTag()) + val readingState = getInteractiveStoryReadingState(rootHint.event.addressTag()) val readingStateEvent = readingState.event as? InteractiveStoryReadingStateEvent if (readingStateEvent != null) { - account.updateInteractiveStoryReadingState(readingStateEvent, readingScene, sceneNoteRelayHint) + account.updateInteractiveStoryReadingState(readingStateEvent, readingSceneHint) } else { - val rootNoteRelayHint = LocalCache.getOrCreateAddressableNote(root.address()).relayHintUrl() - - account.createInteractiveStoryReadingState(root, rootNoteRelayHint, readingScene, sceneNoteRelayHint) + account.createInteractiveStoryReadingState(rootHint, readingSceneHint) } } } diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip18Reposts/RepostAction.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip18Reposts/RepostAction.kt index f99c9f643..0da993242 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip18Reposts/RepostAction.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip18Reposts/RepostAction.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.commons.model.nip18Reposts import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer +import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent import com.vitorpamplona.quartz.nip18Reposts.RepostEvent @@ -35,34 +35,26 @@ object RepostAction { /** * Creates a signed repost event. * - * @param event The event to repost + * @param eventHint The event to repost * @param signer The NostrSigner to sign the event - * @param noteHint Optional relay hint where the note was seen - * @param authorHint Optional relay hint for the author's outbox * @return Signed repost event ready to broadcast * @throws IllegalStateException if signer is not writeable */ suspend fun repost( - event: Event, + eventHint: EventHintBundle, signer: NostrSigner, - noteHint: String? = null, - authorHint: String? = null, ): Event { if (!signer.isWriteable()) { throw IllegalStateException("Cannot repost: signer is not writeable") } - // Normalize relay hints - val normalizedNoteHint = noteHint?.let { RelayUrlNormalizer.normalizeOrNull(it) } - val normalizedAuthorHint = authorHint?.let { RelayUrlNormalizer.normalizeOrNull(it) } - // Use NIP-18 RepostEvent (kind 6) for text notes (kind 1) // Use GenericRepostEvent (kind 16) for all other kinds val template = - if (event.kind == 1) { - RepostEvent.build(event, normalizedNoteHint, normalizedAuthorHint) + if (eventHint.event.kind == 1) { + RepostEvent.build(eventHint) } else { - GenericRepostEvent.build(event, normalizedNoteHint, normalizedAuthorHint) + GenericRepostEvent.build(eventHint) } return signer.sign(template) @@ -86,10 +78,8 @@ object RepostAction { if (!signer.isWriteable()) return null if (note.hasBoostedInTheLast5Minutes(signer.pubKey)) return null - val noteEvent = note.event ?: return null - val noteHint = note.relayHintUrl()?.url - val authorHint = note.author?.bestRelayHint()?.url + val hint = note.toEventHint() ?: return null - return repost(noteEvent, signer, noteHint, authorHint) + return repost(hint, signer) } } diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip25Reactions/ReactionAction.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip25Reactions/ReactionAction.kt index 249dc74e9..5a1511b74 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip25Reactions/ReactionAction.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip25Reactions/ReactionAction.kt @@ -24,7 +24,6 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip17Dm.NIP17Factory import com.vitorpamplona.quartz.nip17Dm.base.NIP17Group @@ -49,18 +48,14 @@ object ReactionAction { * @throws IllegalStateException if signer is not writeable */ suspend fun reactTo( - event: Event, + eventHint: EventHintBundle, reaction: String, signer: NostrSigner, - relayHint: String? = null, ): ReactionEvent { if (!signer.isWriteable()) { throw IllegalStateException("Cannot react: signer is not writeable") } - val normalizedRelayHint = relayHint?.let { RelayUrlNormalizer.normalizeOrNull(it) } - val eventHint = EventHintBundle(event, normalizedRelayHint) - // Handle custom emoji reactions (format: ":emoji_name:") val template = if (reaction.startsWith(":")) { @@ -82,10 +77,9 @@ object ReactionAction { * Creates a "like" reaction ("+"). */ suspend fun like( - event: Event, + event: EventHintBundle, signer: NostrSigner, - relayHint: String? = null, - ): ReactionEvent = reactTo(event, "+", signer, relayHint) + ): ReactionEvent = reactTo(event, "+", signer) /** * Advanced: React to an event with support for NIP-17 private groups. @@ -102,7 +96,6 @@ object ReactionAction { * @param onPrivate Callback for private group reactions (returns NIP17Factory.Result) */ suspend fun reactToWithGroupSupport( - event: Event, eventHint: EventHintBundle, reaction: String, signer: NostrSigner, @@ -113,6 +106,8 @@ object ReactionAction { throw IllegalStateException("Cannot react: signer is not writeable") } + val event = eventHint.event + // Check if this is a NIP-17 private group event if (event is NIP17Group) { val users = event.groupMembers().toList() @@ -185,9 +180,8 @@ object ReactionAction { if (!signer.isWriteable()) return if (note.hasReacted(by, reaction)) return - val noteEvent = note.event ?: return val eventHint = note.toEventHint() ?: return - reactToWithGroupSupport(noteEvent, eventHint, reaction, signer, onPublic, onPrivate) + reactToWithGroupSupport(eventHint, reaction, signer, onPublic, onPrivate) } } diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/NoteActions.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/NoteActions.kt index af9106f90..4e940173d 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/NoteActions.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/NoteActions.kt @@ -70,6 +70,7 @@ import com.vitorpamplona.amethyst.desktop.cache.DesktopLocalCache import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager import com.vitorpamplona.amethyst.desktop.nwc.NwcPaymentHandler import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter @@ -538,7 +539,8 @@ fun NoteActionsRow( if (!isLiked) { scope.launch { reactToNote( - event = event, + // TODO: Bring a hint to where the event came from + event = EventHintBundle(event, null), reaction = "+", account = account, relayManager = relayManager, @@ -578,7 +580,8 @@ fun NoteActionsRow( if (!isReposted) { scope.launch { repostNote( - event = event, + // TODO: Bring a hint to where the event came from + event = EventHintBundle(event, null), account = account, relayManager = relayManager, ) @@ -808,7 +811,7 @@ fun NoteActionsRow( * Creates a reaction event and broadcasts to relays. */ private suspend fun reactToNote( - event: Event, + event: EventHintBundle, reaction: String, account: AccountState.LoggedIn, relayManager: DesktopRelayConnectionManager, @@ -893,7 +896,7 @@ private suspend fun removeBookmark( * Creates a repost event and broadcasts to relays. */ private suspend fun repostNote( - event: Event, + event: EventHintBundle, account: AccountState.LoggedIn, relayManager: DesktopRelayConnectionManager, ) { diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt index 6a32f886e..51d45eb74 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt @@ -28,7 +28,7 @@ import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.core.builder -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag @@ -83,17 +83,16 @@ class InteractiveStoryReadingStateEvent( fun update( base: InteractiveStoryReadingStateEvent, - currentScene: InteractiveStoryBaseEvent, - currentSceneRelay: NormalizedRelayUrl?, + currentScene: EventHintBundle, createdAt: Long = TimeUtils.now(), ): EventTemplate { val rootTag = base.dTag() - val sceneTag = currentScene.aTag(currentSceneRelay) + val sceneTag = ATag(currentScene.event.address(), currentScene.relay) val status = if (rootTag == sceneTag.toTag()) { ReadStatusTag.STATUS.NEW - } else if (currentScene.options().isEmpty()) { + } else if (currentScene.event.options().isEmpty()) { ReadStatusTag.STATUS.DONE } else { ReadStatusTag.STATUS.READING @@ -109,34 +108,32 @@ class InteractiveStoryReadingStateEvent( } fun build( - root: InteractiveStoryBaseEvent, - rootRelay: NormalizedRelayUrl?, - currentScene: InteractiveStoryBaseEvent, - currentSceneRelay: NormalizedRelayUrl?, + root: EventHintBundle, + currentScene: EventHintBundle, createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = eventTemplate(KIND, "", createdAt) { - val rootTag = root.aTag(rootRelay) - val sceneTag = currentScene.aTag(currentSceneRelay) + val rootTag = ATag(root.event.address(), root.relay) + val sceneTag = ATag(currentScene.event.address(), currentScene.relay) val status = if (rootTag == sceneTag) { ReadStatusTag.STATUS.NEW - } else if (currentScene.options().isEmpty()) { + } else if (currentScene.event.options().isEmpty()) { ReadStatusTag.STATUS.DONE } else { ReadStatusTag.STATUS.READING } dTag(rootTag.toTag()) - alt(root.title()?.let { ALT2 + it } ?: ALT1) + alt(root.event.title()?.let { ALT2 + it } ?: ALT1) rootScene(rootTag) currentScene(sceneTag) status(status) - root.title()?.let { storyTitle(it) } - root.summary()?.let { storyImage(it) } - root.image()?.let { storySummary(it) } + root.event.title()?.let { storyTitle(it) } + root.event.summary()?.let { storyImage(it) } + root.event.image()?.let { storySummary(it) } initializer() } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nipsOnNostr/NipTextEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nipsOnNostr/NipTextEvent.kt index f1de38137..992bbb51d 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nipsOnNostr/NipTextEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nipsOnNostr/NipTextEvent.kt @@ -32,7 +32,6 @@ import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag @@ -71,8 +70,6 @@ class NipTextEvent( override fun dTag() = tags.dTag() - override fun aTag(relayHint: NormalizedRelayUrl?) = ATag(kind, pubKey, dTag(), relayHint) - override fun address() = Address(kind, pubKey, dTag()) override fun addressTag() = Address.assemble(kind, pubKey, dTag()) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressableEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressableEvent.kt index 9fbdde36b..2f5732d44 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressableEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressableEvent.kt @@ -21,15 +21,11 @@ package com.vitorpamplona.quartz.nip01Core.core import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag @Immutable interface AddressableEvent : IEvent { fun dTag(): String - fun aTag(relayHint: NormalizedRelayUrl? = null): ATag - fun address(): Address fun addressTag(): String diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt index 9ecaa83d6..4f9025527 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt @@ -21,8 +21,6 @@ package com.vitorpamplona.quartz.nip01Core.core import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag @Immutable @@ -38,8 +36,6 @@ open class BaseAddressableEvent( AddressableEvent { override fun dTag() = tags.dTag() - override fun aTag(relayHint: NormalizedRelayUrl?) = ATag(kind, pubKey, dTag(), relayHint) - override fun address() = Address(kind, pubKey, dTag()) /** diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt index 622f854d2..f236a2c1c 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt @@ -21,8 +21,6 @@ package com.vitorpamplona.quartz.nip01Core.core import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag @Immutable open class BaseReplaceableEvent( @@ -33,11 +31,10 @@ open class BaseReplaceableEvent( tags: TagArray, content: String, sig: HexKey, -) : BaseAddressableEvent(id, pubKey, createdAt, kind, tags, content, sig) { +) : Event(id, pubKey, createdAt, kind, tags, content, sig), + AddressableEvent { override fun dTag() = FIXED_D_TAG - override fun aTag(relayHint: NormalizedRelayUrl?) = ATag(kind, pubKey, FIXED_D_TAG, relayHint) - override fun address(): Address = Address(kind, pubKey, dTag()) /** diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/TagArrayBuilderExt.kt index 1cce516a2..ca62c97c6 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/TagArrayBuilderExt.kt @@ -20,11 +20,20 @@ */ package com.vitorpamplona.quartz.nip01Core.tags.aTag +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl fun TagArrayBuilder.aTag(tag: ATag) = add(tag.toATagArray()) +fun TagArrayBuilder.aTag( + address: Address, + relayHint: NormalizedRelayUrl? = null, +) = add(ATag.assemble(address, relayHint)) + fun TagArrayBuilder.aTags(tag: List) = addAll(tag.map { it.toATagArray() }) fun TagArrayBuilder.removeATag(tag: ATag) = this.removeIf(ATag::isSameAddress, tag.toATagArray()) + +fun TagArrayBuilder.removeAddress(address: Address) = this.removeIf(ATag::isSameAddress, ATag.assemble(address, null)) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt index b3df7fad8..2bd326595 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt @@ -89,7 +89,7 @@ class DeletionEvent( deleteEvents.forEach { eTag(ETag(it.id)) if (it is AddressableEvent) { - aTag(it.aTag()) + aTag(it.address()) } } @@ -108,7 +108,7 @@ class DeletionEvent( deleteEvents.forEach { if (it is AddressableEvent) { - aTag(it.aTag()) + aTag(it.address()) } } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/GenericRepostEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/GenericRepostEvent.kt index 9420bb11d..9ef37f5d8 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/GenericRepostEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/GenericRepostEvent.kt @@ -26,9 +26,9 @@ import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider +import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag @@ -38,7 +38,6 @@ import com.vitorpamplona.quartz.nip01Core.tags.events.eTag import com.vitorpamplona.quartz.nip01Core.tags.kinds.kind import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTag -import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.lastNotNullOfOrNull @@ -93,45 +92,28 @@ class GenericRepostEvent( const val ALT = "Generic repost" fun build( - boostedPost: Event, - eventSourceRelay: NormalizedRelayUrl?, - authorHomeRelay: NormalizedRelayUrl?, + eventHint: EventHintBundle, createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, - ) = eventTemplate(KIND, boostedPost.toJson(), createdAt) { + ) = eventTemplate(KIND, eventHint.event.toJson(), createdAt) { + val boostedPost = eventHint.event + alt(ALT) kind(boostedPost.kind) - pTag(PTag(boostedPost.pubKey, authorHomeRelay)) - eTag(ETag(boostedPost.id, eventSourceRelay, boostedPost.pubKey)) + pTag(PTag(boostedPost.pubKey, eventHint.authorHomeRelay)) + eTag(ETag(boostedPost.id, eventHint.relay, boostedPost.pubKey)) if (boostedPost is AddressableEvent) { - aTag(boostedPost.aTag(eventSourceRelay)) + aTag(boostedPost.address(), eventHint.relay) } initializer() } suspend fun create( - boostedPost: Event, + eventHint: EventHintBundle, signer: NostrSigner, createdAt: Long = TimeUtils.now(), - ): GenericRepostEvent { - val content = boostedPost.toJson() - - val tags = - mutableListOf( - arrayOf("e", boostedPost.id), - arrayOf("p", boostedPost.pubKey), - ) - - if (boostedPost is AddressableEvent) { - tags.add(arrayOf("a", boostedPost.aTag().toTag())) - } - - tags.add(arrayOf("k", "${boostedPost.kind}")) - tags.add(AltTag.assemble(ALT)) - - return signer.sign(createdAt, KIND, tags.toTypedArray(), content) - } + ): GenericRepostEvent = signer.sign(build(eventHint, createdAt)) } } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/RepostEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/RepostEvent.kt index a8abc54a2..39a6391a6 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/RepostEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/RepostEvent.kt @@ -26,9 +26,10 @@ import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider +import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTag @@ -82,7 +83,7 @@ class RepostEvent( fun containedPost() = try { fromJson(content) - } catch (e: Exception) { + } catch (_: Exception) { null } @@ -91,22 +92,28 @@ class RepostEvent( const val ALT = "Repost event" fun build( - boostedPost: Event, - eventSourceRelay: NormalizedRelayUrl?, - authorHomeRelay: NormalizedRelayUrl?, + eventHint: EventHintBundle, createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, - ) = eventTemplate(KIND, boostedPost.toJson(), createdAt) { + ) = eventTemplate(KIND, eventHint.event.toJson(), createdAt) { + val boostedPost = eventHint.event + alt(ALT) - pTag(PTag(boostedPost.pubKey, authorHomeRelay)) - eTag(ETag(boostedPost.id, eventSourceRelay, boostedPost.pubKey)) + pTag(PTag(boostedPost.pubKey, eventHint.authorHomeRelay)) + eTag(ETag(boostedPost.id, eventHint.relay, boostedPost.pubKey)) if (boostedPost is AddressableEvent) { - aTag(boostedPost.aTag(eventSourceRelay)) + aTag(boostedPost.address(), eventHint.relay) } kind(boostedPost.kind) initializer() } + + suspend fun create( + eventHint: EventHintBundle, + signer: NostrSigner, + createdAt: Long = TimeUtils.now(), + ): RepostEvent = signer.sign(build(eventHint, createdAt)) } } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt index 15a283c23..6eabe0f37 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt @@ -31,9 +31,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags import com.vitorpamplona.quartz.nip01Core.tags.people.PTag @@ -119,8 +117,6 @@ class LongTextNoteEvent( override fun dTag() = tags.dTag() - override fun aTag(relayHint: NormalizedRelayUrl?) = ATag(kind, pubKey, dTag(), relayHint) - override fun address() = Address(kind, pubKey, dTag()) override fun addressTag() = Address.assemble(kind, pubKey, dTag()) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip25Reactions/ReactionEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip25Reactions/ReactionEvent.kt index a7ff4fc17..69901c396 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip25Reactions/ReactionEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip25Reactions/ReactionEvent.kt @@ -91,7 +91,7 @@ class ReactionEvent( ) = eventTemplate(KIND, reaction, createdAt) { eTag(reactedTo.toETag()) if (reactedTo.event is AddressableEvent) { - aTag(reactedTo.event.aTag(reactedTo.relay)) + aTag(reactedTo.event.address(), reactedTo.relay) } pTag(reactedTo.event.pubKey, reactedTo.relay) kind(reactedTo.event.kind) @@ -104,7 +104,7 @@ class ReactionEvent( ) = eventTemplate(KIND, reaction.toContentEncode(), createdAt) { eTag(reactedTo.toETag()) if (reactedTo.event is AddressableEvent) { - aTag(reactedTo.event.aTag(reactedTo.relay)) + aTag(reactedTo.event.address(), reactedTo.relay) } pTag(reactedTo.event.pubKey, reactedTo.relay) kind(reactedTo.event.kind) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/EmojiPackSelectionEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/EmojiPackSelectionEvent.kt index 9515507f4..a2174bf87 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/EmojiPackSelectionEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/EmojiPackSelectionEvent.kt @@ -78,7 +78,7 @@ class EmojiPackSelectionEvent( createdAt: Long = TimeUtils.now(), updater: TagArrayBuilder.() -> Unit = {}, ) = eventUpdate(currentSelection, createdAt) { - removePack(packToRemove.aTag(null)) + removePack(packToRemove.address()) updater() } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/TagArrayBuilderExt.kt index e3d6dae4b..c97a08a7f 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/TagArrayBuilderExt.kt @@ -20,14 +20,15 @@ */ package com.vitorpamplona.quartz.nip30CustomEmoji.selection +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTag import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTags -import com.vitorpamplona.quartz.nip01Core.tags.aTag.removeATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.removeAddress fun TagArrayBuilder.pack(tag: ATag) = aTag(tag) fun TagArrayBuilder.packs(tags: List) = aTags(tags) -fun TagArrayBuilder.removePack(tag: ATag) = removeATag(tag) +fun TagArrayBuilder.removePack(address: Address) = removeAddress(address) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt index 0af55aac4..295c38fd4 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt @@ -34,7 +34,6 @@ import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag @@ -129,8 +128,6 @@ class WikiNoteEvent( override fun dTag() = tags.dTag() - override fun aTag(relayHint: NormalizedRelayUrl?) = ATag(kind, pubKey, dTag(), relayHint) - override fun address() = Address(kind, pubKey, dTag()) override fun addressTag() = Address.assemble(kind, pubKey, dTag()) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt index b204dafdb..efa2cec2b 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt @@ -104,7 +104,7 @@ class LnZapRequestEvent( AltTag.assemble(ALT), ) if (zappedEvent is AddressableEvent) { - tags = tags + listOf(arrayOf("a", zappedEvent.aTag().toTag())) + tags = tags + listOf(ATag.assemble(zappedEvent.address(), null)) } if (pollOption != null && pollOption >= 0) { tags = tags + listOf(arrayOf(PollOptionTag.TAG_NAME, pollOption.toString()))