From c25d64558ed85d457b97e82bc8328a9b1e10658b Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 15 Jan 2025 11:48:01 -0500 Subject: [PATCH] - Normalizes the use of ETag - Creates a BaseReplaceable event to avoid duplicates of empty d tags. --- .../vitorpamplona/amethyst/model/Account.kt | 20 ++++--- .../amethyst/model/LocalCache.kt | 33 +++++++++--- .../ui/dal/ChatroomListKnownFeedFilter.kt | 4 +- .../amethyst/ui/feeds/FeedContentState.kt | 2 +- .../ui/note/NIP05VerificationDisplay.kt | 9 ++-- .../amethyst/ui/note/types/Highlight.kt | 10 ++-- .../ui/note/types/TextModification.kt | 6 +-- .../amethyst/ui/screen/FollowListState.kt | 2 +- .../ui/screen/loggedIn/AccountViewModel.kt | 24 ++++++++- .../screen/loggedIn/profile/ProfileScreen.kt | 11 ++-- .../quartz/blossom/BlossomServersEvent.kt | 9 ++-- .../edits/PrivateOutboxRelayListEvent.kt | 9 ++-- .../InteractiveStoryBaseEvent.kt | 1 - .../InteractiveStoryPrologueEvent.kt | 2 +- .../InteractiveStoryReadingStateEvent.kt | 3 +- .../InteractiveStorySceneEvent.kt | 2 +- .../nip01Core/core/BaseAddressableEvent.kt | 4 +- .../nip01Core/core/BaseReplaceableEvent.kt | 49 +++++++++++++++++ .../nip01Core/tags/addressables/ATag.kt | 53 +++++++++++++++++-- .../tags/addressables/TagArrayExt.kt | 18 +++---- .../quartz/nip01Core/tags/dTags/DTag.kt | 45 ++++++++++++++++ .../quartz/nip01Core/tags/dTags/EventExt.kt | 25 +++++++++ .../tags/dTags/TagArrayBuilderExt.kt | 25 +++++++++ .../nip01Core/tags/dTags/TagArrayExt.kt | 26 +++++++++ .../tags/events}/ETag.kt | 30 ++++++++--- .../quartz/nip01Core/tags/events/EventExt.kt | 6 ++- .../nip01Core/tags/events/TagArrayExt.kt | 16 +++--- .../quartz/nip09Deletions/DeletionEvent.kt | 3 ++ .../vitorpamplona/quartz/nip13Pow/PoWTag.kt | 2 +- .../quartz/nip14Subject/SubjectTag.kt | 7 +-- .../nip17Dm/ChatMessageRelayListEvent.kt | 9 ++-- .../quartz/nip19Bech32/entities/NAddress.kt | 2 +- .../quartz/nip22Comments/CommentEvent.kt | 2 +- .../nip23LongContent/LongTextNoteEvent.kt | 4 +- .../nip28PublicChat/ChannelListEvent.kt | 3 -- .../EmojiPackSelectionEvent.kt | 23 ++------ .../quartz/nip37Drafts/DraftEvent.kt | 2 +- .../nip50Search/SearchRelayListEvent.kt | 9 ++-- .../quartz/nip51Lists/GeneralListEvent.kt | 1 - .../quartz/nip51Lists/MuteListEvent.kt | 2 +- .../quartz/nip54Wiki/WikiNoteEvent.kt | 2 +- .../AdvertisedRelayListEvent.kt | 9 ++-- .../quartz/nip68Picture/PictureEvent.kt | 2 +- .../nip72ModCommunities/CommunityListEvent.kt | 2 +- .../AppRecommendationEvent.kt | 1 - .../nip96FileStorage/FileServersEvent.kt | 9 ++-- 46 files changed, 393 insertions(+), 145 deletions(-) create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/DTag.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/EventExt.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayBuilderExt.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayExt.kt rename quartz/src/main/java/com/vitorpamplona/quartz/{nip10Notes => nip01Core/tags/events}/ETag.kt (68%) 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 69fde9b86..b300173e3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -74,17 +74,18 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag import com.vitorpamplona.quartz.nip01Core.tags.addressables.taggedAddresses -import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents +import com.vitorpamplona.quartz.nip01Core.tags.events.ETag +import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEventIds import com.vitorpamplona.quartz.nip01Core.tags.geohash.geohashes import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags import com.vitorpamplona.quartz.nip01Core.tags.people.hasAnyTaggedUser import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser +import com.vitorpamplona.quartz.nip01Core.tags.people.taggedUsers import com.vitorpamplona.quartz.nip02FollowList.Contact import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import com.vitorpamplona.quartz.nip03Timestamp.OtsEvent import com.vitorpamplona.quartz.nip04Dm.PrivateDmEvent import com.vitorpamplona.quartz.nip09Deletions.DeletionEvent -import com.vitorpamplona.quartz.nip10Notes.ETag import com.vitorpamplona.quartz.nip10Notes.PTag import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip17Dm.ChatMessageRelayListEvent @@ -954,7 +955,7 @@ class Account( onReady: (LiveFollowList) -> Unit, ) { listEvent.privateTags(signer) { privateTagList -> - val users = (listEvent.bookmarkedPeople() + listEvent.filterUsers(privateTagList)).toSet() + val users = (listEvent.taggedUsers() + listEvent.filterUsers(privateTagList)).toSet() onReady( LiveFollowList( authors = users, @@ -970,6 +971,11 @@ class Account( } } + fun decryptPeopleList( + event: GeneralListEvent, + onReady: (Array>) -> Unit, + ) = event.privateTags(signer, onReady) + suspend fun waitToDecrypt(peopleListFollows: GeneralListEvent): LiveFollowList? = tryAndWait { continuation -> decryptLiveFollows(peopleListFollows) { @@ -2445,7 +2451,7 @@ class Account( directMentionsNotes .mapNotNullTo(HashSet(directMentionsNotes.size)) { note -> if (note !is AddressableNote) { - ETag(note.idHex, note.author?.pubkeyHex, note.relayHintUrl()) + ETag(note.idHex, note.relayHintUrl(), note.author?.pubkeyHex) } else { null } @@ -2556,7 +2562,7 @@ class Account( directMentionsNotes .mapNotNullTo(HashSet(directMentionsNotes.size)) { note -> if (note !is AddressableNote) { - ETag(note.idHex, note.author?.pubkeyHex, note.relayHintUrl()) + ETag(note.idHex, note.relayHintUrl(), note.author?.pubkeyHex) } else { null } @@ -3520,7 +3526,7 @@ class Account( if (note is AddressableNote) { return userProfile().latestBookmarkList?.taggedAddresses()?.contains(note.address) == true } else { - return userProfile().latestBookmarkList?.taggedEvents()?.contains(note.idHex) == true + return userProfile().latestBookmarkList?.taggedEventIds()?.contains(note.idHex) == true } } @@ -3675,7 +3681,7 @@ class Account( fun selectedChatsFollowList(): Set { val contactList = userProfile().latestContactList - return contactList?.taggedEvents()?.toSet() ?: DefaultChannels + return contactList?.taggedEventIds()?.toSet() ?: DefaultChannels } fun sendChangeChannel( 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 7bebdb5bc..b1e88fb1a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -57,9 +57,10 @@ import com.vitorpamplona.quartz.nip01Core.hasValidSignature import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag import com.vitorpamplona.quartz.nip01Core.tags.addressables.mapTaggedAddress import com.vitorpamplona.quartz.nip01Core.tags.addressables.taggedAddresses -import com.vitorpamplona.quartz.nip01Core.tags.events.forEachTaggedEvent +import com.vitorpamplona.quartz.nip01Core.tags.events.ETag +import com.vitorpamplona.quartz.nip01Core.tags.events.forEachTaggedEventId import com.vitorpamplona.quartz.nip01Core.tags.events.isTaggedEvent -import com.vitorpamplona.quartz.nip01Core.tags.events.mapTaggedEvent +import com.vitorpamplona.quartz.nip01Core.tags.events.mapTaggedEventId import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUsers import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent @@ -78,7 +79,6 @@ import com.vitorpamplona.quartz.nip18Reposts.RepostEvent import com.vitorpamplona.quartz.nip19Bech32.decodeEventIdAsHexOrNull import com.vitorpamplona.quartz.nip19Bech32.decodePublicKeyAsHexOrNull import com.vitorpamplona.quartz.nip19Bech32.isATag -import com.vitorpamplona.quartz.nip19Bech32.parse import com.vitorpamplona.quartz.nip22Comments.CommentEvent import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent @@ -239,7 +239,7 @@ object LocalCache { private fun updateObservables(event: Event) { observablesByKindAndETag[event.kind]?.let { observablesOfKind -> - event.forEachTaggedEvent { + event.forEachTaggedEventId { observablesOfKind[it]?.updateIfMatches(event) } } @@ -274,6 +274,8 @@ object LocalCache { fun getNoteIfExists(key: String): Note? = addressables.get(key) ?: notes.get(key) + fun getNoteIfExists(key: ETag): Note? = notes.get(key.eventId) + fun getChannelIfExists(key: String): Channel? = channels.get(key) fun getNoteIfExists(event: Event): Note? = @@ -290,6 +292,15 @@ object LocalCache { getOrCreateNote(event.id) } + fun checkGetOrCreateNote(etag: ETag): Note? { + checkNotInMainThread() + + if (isValidHex(etag.eventId)) { + return getOrCreateNote(etag) + } + return null + } + fun checkGetOrCreateNote(key: String): Note? { checkNotInMainThread() @@ -401,6 +412,16 @@ object LocalCache { return note } + fun getOrCreateNote(key: ETag): Note { + val note = getOrCreateNote(key.eventId) + // Loads the user outside a Syncronized block to avoid blocking + val possibleAuthor = key.authorPubKeyHex + if (note.author == null && possibleAuthor != null) { + note.author = checkGetOrCreateUser(possibleAuthor) + } + return note + } + fun consume( event: MetadataEvent, relay: Relay?, @@ -681,7 +702,7 @@ object LocalCache { event.tagsWithoutCitations().mapNotNull { checkGetOrCreateNote(it) } is DraftEvent -> { - event.mapTaggedEvent { checkGetOrCreateNote(it) } + event.mapTaggedAddress { checkGetOrCreateAddressableNote(it) } + event.mapTaggedEventId { checkGetOrCreateNote(it) } + event.mapTaggedAddress { checkGetOrCreateAddressableNote(it) } } else -> emptyList() @@ -1562,7 +1583,7 @@ object LocalCache { note.loadEvent(event, author, emptyList()) event.editedNote()?.let { - checkGetOrCreateNote(it)?.let { editedNote -> + checkGetOrCreateNote(it.eventId)?.let { editedNote -> modificationCache.remove(editedNote.idHex) // must update list of Notes to quickly update the user. editedNote.liveSet?.innerModifications?.invalidateData() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListKnownFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListKnownFeedFilter.kt index 0d8200ad1..8a7073c22 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListKnownFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListKnownFeedFilter.kt @@ -24,7 +24,7 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.actions.relays.updated -import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents +import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEventIds import com.vitorpamplona.quartz.nip17Dm.ChatroomKey import com.vitorpamplona.quartz.nip17Dm.ChatroomKeyable import com.vitorpamplona.quartz.nip28PublicChat.ChannelMessageEvent @@ -141,7 +141,7 @@ class ChatroomListKnownFeedFilter( account .userProfile() .latestContactList - ?.taggedEvents() + ?.taggedEventIds() ?.toSet() ?: emptySet() val newRelevantPublicMessages = mutableMapOf() newItems diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentState.kt index 5aa526208..2aab5999d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentState.kt @@ -120,7 +120,7 @@ class FeedContentState( if (deletionEvents.isEmpty()) { oldNotesState.feed.value.list } else { - val deletedEventIds = deletionEvents.flatMapTo(HashSet()) { it.deleteEvents() } + val deletedEventIds = deletionEvents.flatMapTo(HashSet()) { it.deleteEventIds() } val deletedEventAddresses = deletionEvents.flatMapTo(HashSet()) { it.deleteAddresses() } oldNotesState.feed.value.list .filter { !it.wasOrShouldBeDeletedBy(deletedEventIds, deletedEventAddresses) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt index 83a1c9143..f244233b1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt @@ -75,6 +75,7 @@ import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.nip01Core.UserMetadata import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag import com.vitorpamplona.quartz.nip01Core.tags.addressables.firstTaggedAddress +import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.firstTaggedEvent import com.vitorpamplona.quartz.nip38UserStatus.StatusEvent import com.vitorpamplona.quartz.utils.TimeUtils @@ -264,7 +265,7 @@ fun DisplayStatus( event.dTag(), event.firstTaggedUrl()?.ifBlank { null }, event.firstTaggedAddress(), - event.firstTaggedEvent()?.ifBlank { null }, + event.firstTaggedEvent(), accountViewModel, nav, ) @@ -276,7 +277,7 @@ fun DisplayStatusInner( type: String, url: String?, nostrATag: ATag?, - nostrHexID: String?, + nostrETag: ETag?, accountViewModel: AccountViewModel, nav: INav, ) { @@ -335,8 +336,8 @@ fun DisplayStatusInner( } } } - } else if (nostrHexID != null) { - LoadNote(baseNoteHex = nostrHexID, accountViewModel) { + } else if (nostrETag != null) { + LoadNote(baseNoteHex = nostrETag.eventId, accountViewModel) { if (it != null) { Spacer(modifier = StdHorzSpacer) IconButton( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt index e3aae9135..eaa07279b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt @@ -53,9 +53,9 @@ import com.vitorpamplona.amethyst.ui.components.measureSpaceWidth import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.quartz.nip01Core.HexKey import com.vitorpamplona.quartz.nip01Core.core.firstTagValueFor import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList import com.vitorpamplona.quartz.nip10Notes.BaseTextNoteEvent import com.vitorpamplona.quartz.nip19Bech32.toNIP19 @@ -100,7 +100,7 @@ fun DisplayHighlight( authorHex: String?, url: String?, postAddress: ATag?, - postVersion: HexKey?, + postVersion: ETag?, makeItShort: Boolean, canPreview: Boolean, quotesLeft: Int, @@ -150,7 +150,7 @@ private fun DisplayQuoteAuthor( authorHex: String?, baseUrl: String?, postAddress: ATag?, - postVersion: HexKey?, + postVersion: ETag?, accountViewModel: AccountViewModel, nav: INav, ) { @@ -181,14 +181,14 @@ private fun DisplayQuoteAuthor( } var version by remember { - mutableStateOf(postVersion?.let { accountViewModel.getNoteIfExists(it) }) + mutableStateOf(postVersion?.let { accountViewModel.getNoteIfExists(it.eventId) }) } if (version == null && postVersion != null) { LaunchedEffect(key1 = postVersion) { val newNote = withContext(Dispatchers.IO) { - accountViewModel.getOrCreateNote(postVersion) + accountViewModel.getOrCreateNote(postVersion.eventId) } if (version != newNote) { version = newNote diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt index 265e104dc..ebdbd62a7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt @@ -84,13 +84,13 @@ fun RenderTextModificationEvent( val isAuthorTheLoggedUser = remember { val authorOfTheOriginalNote = - noteEvent.editedNote()?.let { accountViewModel.getNoteIfExists(it)?.author } + noteEvent.editedNote()?.let { accountViewModel.getNoteIfExists(it.eventId)?.author?.pubkeyHex ?: it.authorPubKeyHex } mutableStateOf(accountViewModel.isLoggedUser(authorOfTheOriginalNote)) } noteEvent.editedNote()?.let { - LoadNote(baseNoteHex = it, accountViewModel = accountViewModel) { baseOriginalNote -> + LoadNote(baseNoteHex = it.eventId, accountViewModel = accountViewModel) { baseOriginalNote -> baseOriginalNote?.let { } } @@ -128,7 +128,7 @@ fun RenderTextModificationEvent( } noteEvent.editedNote()?.let { - LoadNote(baseNoteHex = it, accountViewModel = accountViewModel) { baseNote -> + LoadNote(baseNoteHex = it.eventId, accountViewModel = accountViewModel) { baseNote -> baseNote?.let { val noteState by baseNote.live().metadata.observeAsState() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FollowListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FollowListState.kt index 48ed1482a..a1d9026e6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FollowListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FollowListState.kt @@ -140,7 +140,7 @@ class FollowListState( ( noteEvent is DeletionEvent && ( - noteEvent.deleteEvents().any { + noteEvent.deleteEventIds().any { LocalCache.getNoteIfExists(it)?.event is PeopleListEvent } || noteEvent.deleteAddresses().any { 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 f7232fc5b..d97bb5edd 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 @@ -82,6 +82,7 @@ import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser +import com.vitorpamplona.quartz.nip01Core.tags.people.taggedUsers import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation import com.vitorpamplona.quartz.nip17Dm.ChatMessageRelayListEvent import com.vitorpamplona.quartz.nip17Dm.ChatroomKey @@ -99,6 +100,7 @@ import com.vitorpamplona.quartz.nip19Bech32.entities.NSec import com.vitorpamplona.quartz.nip37Drafts.DraftEvent import com.vitorpamplona.quartz.nip47WalletConnect.Response import com.vitorpamplona.quartz.nip50Search.SearchRelayListEvent +import com.vitorpamplona.quartz.nip51Lists.GeneralListEvent import com.vitorpamplona.quartz.nip56Reports.ReportEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent @@ -1071,7 +1073,7 @@ class AccountViewModel( viewModelScope.launch(Dispatchers.IO) { runOnIO() } } - suspend fun checkGetOrCreateUser(key: HexKey): User? = LocalCache.checkGetOrCreateUser(key) + fun checkGetOrCreateUser(key: HexKey): User? = LocalCache.checkGetOrCreateUser(key) override suspend fun getOrCreateUser(key: HexKey): User = LocalCache.getOrCreateUser(key) @@ -1201,7 +1203,7 @@ class AccountViewModel( hexList: List, onReady: (ImmutableList) -> Unit, ) { - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(Dispatchers.Default) { onReady( hexList .mapNotNull { hex -> checkGetOrCreateUser(hex) } @@ -1212,6 +1214,24 @@ class AccountViewModel( } } + fun loadUsers( + event: GeneralListEvent, + onReady: (ImmutableList) -> Unit, + ) { + viewModelScope.launch(Dispatchers.Default) { + account.decryptPeopleList(event) { privateTagList -> + onReady( + (event.taggedUsers() + event.filterUsers(privateTagList)) + .toSet() + .mapNotNull { hex -> checkGetOrCreateUser(hex) } + .sortedBy { account.isFollowing(it) } + .reversed() + .toImmutableList(), + ) + } + } + } + fun checkVideoIsOnline( videoUrl: String, onDone: (Boolean) -> Unit, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/ProfileScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/ProfileScreen.kt index c0c188f1b..fb71eb80f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/ProfileScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/ProfileScreen.kt @@ -177,6 +177,7 @@ import com.vitorpamplona.amethyst.ui.theme.ZeroPadding import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.userProfileBorderModifier import com.vitorpamplona.quartz.nip01Core.tags.addressables.taggedAddresses +import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList import com.vitorpamplona.quartz.nip39ExtIdentities.GitHubIdentity @@ -1383,7 +1384,7 @@ private fun WatchAndRenderBadgeList( @Composable @OptIn(ExperimentalLayoutApi::class) private fun RenderBadgeList( - list: ImmutableList, + list: ImmutableList, loadProfilePicture: Boolean, loadRobohash: Boolean, nav: INav, @@ -1398,17 +1399,17 @@ private fun RenderBadgeList( @Composable private fun LoadAndRenderBadge( - badgeAwardEventHex: String, + badgeAwardEvent: ETag, loadProfilePicture: Boolean, loadRobohash: Boolean, nav: INav, ) { - var baseNote by remember(badgeAwardEventHex) { mutableStateOf(LocalCache.getNoteIfExists(badgeAwardEventHex)) } + var baseNote by remember(badgeAwardEvent) { mutableStateOf(LocalCache.getNoteIfExists(badgeAwardEvent)) } - LaunchedEffect(key1 = badgeAwardEventHex) { + LaunchedEffect(key1 = badgeAwardEvent) { if (baseNote == null) { withContext(Dispatchers.IO) { - baseNote = LocalCache.checkGetOrCreateNote(badgeAwardEventHex) + baseNote = LocalCache.checkGetOrCreateNote(badgeAwardEvent) } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/blossom/BlossomServersEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/blossom/BlossomServersEvent.kt index d2a3f37d1..0c0e265d8 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/blossom/BlossomServersEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/blossom/BlossomServersEvent.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.blossom import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent +import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag import com.vitorpamplona.quartz.nip31Alts.AltTagSerializer @@ -36,9 +36,7 @@ class BlossomServersEvent( tags: Array>, content: String, sig: HexKey, -) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { - override fun dTag() = FIXED_D_TAG - +) : BaseReplaceableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { fun servers(): List = tags.mapNotNull { if (it.size > 1 && it[0] == "server") { @@ -50,12 +48,11 @@ class BlossomServersEvent( companion object { const val KIND = 10063 - const val FIXED_D_TAG = "" const val ALT = "File servers used by the author" fun createAddressATag(pubKey: HexKey): ATag = ATag(KIND, pubKey, FIXED_D_TAG, null) - fun createAddressTag(pubKey: HexKey): String = ATag.assembleATag(KIND, pubKey, FIXED_D_TAG) + fun createAddressTag(pubKey: HexKey): String = ATag.assembleATagId(KIND, pubKey, FIXED_D_TAG) fun createTagArray(servers: List): Array> = servers diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/experimental/edits/PrivateOutboxRelayListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/experimental/edits/PrivateOutboxRelayListEvent.kt index e8a2c6c66..e15f7cfa2 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/experimental/edits/PrivateOutboxRelayListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/experimental/edits/PrivateOutboxRelayListEvent.kt @@ -24,7 +24,7 @@ import android.util.Log import androidx.compose.runtime.Immutable import com.fasterxml.jackson.module.kotlin.readValue import com.vitorpamplona.quartz.nip01Core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent +import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.jackson.EventMapper import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner @@ -43,15 +43,13 @@ class PrivateOutboxRelayListEvent( tags: Array>, content: String, sig: HexKey, -) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { +) : BaseReplaceableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { @Transient private var privateTagsCache: Array>? = null override fun countMemory(): Long = super.countMemory() + pointerSizeInBytes + (privateTagsCache?.sumOf { pointerSizeInBytes + it.sumOf { pointerSizeInBytes + it.bytesUsedInMemory() } } ?: 0) - override fun dTag() = FIXED_D_TAG - fun relays(): List? = tags .mapNotNull { @@ -102,12 +100,11 @@ class PrivateOutboxRelayListEvent( companion object { const val KIND = 10013 - const val FIXED_D_TAG = "" val TAGS = arrayOf(AltTagSerializer.toTagArray("Relay list to store private content from this author")) fun createAddressATag(pubKey: HexKey): ATag = ATag(KIND, pubKey, FIXED_D_TAG, null) - fun createAddressTag(pubKey: HexKey): String = ATag.assembleATag(KIND, pubKey, FIXED_D_TAG) + fun createAddressTag(pubKey: HexKey): String = ATag.assembleATagId(KIND, pubKey, FIXED_D_TAG) fun encryptTags( privateTags: Array>? = null, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryBaseEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryBaseEvent.kt index 753f26017..7446884a4 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryBaseEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryBaseEvent.kt @@ -29,7 +29,6 @@ import com.vitorpamplona.quartz.nip01Core.tags.hashtags.buildHashtagTags import com.vitorpamplona.quartz.nip10Notes.content.buildUrlRefs import com.vitorpamplona.quartz.nip10Notes.content.findHashtags import com.vitorpamplona.quartz.nip10Notes.content.findURLs -import com.vitorpamplona.quartz.nip19Bech32.parse import com.vitorpamplona.quartz.nip30CustomEmoji.EmojiUrl import com.vitorpamplona.quartz.nip31Alts.AltTagSerializer import com.vitorpamplona.quartz.nip36SensitiveContent.ContentWarningSerializer diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryPrologueEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryPrologueEvent.kt index 9952f71a1..3cbffc1cb 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryPrologueEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryPrologueEvent.kt @@ -49,7 +49,7 @@ class InteractiveStoryPrologueEvent( fun createAddressTag( pubKey: HexKey, dtag: String, - ): String = ATag.assembleATag(KIND, pubKey, dtag) + ): String = ATag.assembleATagId(KIND, pubKey, dtag) fun create( baseId: String, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt index de8bf6463..1002f5ca7 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt @@ -27,7 +27,6 @@ import com.vitorpamplona.quartz.nip01Core.core.firstTag import com.vitorpamplona.quartz.nip01Core.core.firstTagValue import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip19Bech32.parse import com.vitorpamplona.quartz.nip31Alts.AltTagSerializer import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.removeTrailingNullsAndEmptyOthers @@ -66,7 +65,7 @@ class InteractiveStoryReadingStateEvent( fun createAddressTag( pubKey: HexKey, dtag: String, - ): String = ATag.assembleATag(KIND, pubKey, dtag) + ): String = ATag.assembleATagId(KIND, pubKey, dtag) fun update( base: InteractiveStoryReadingStateEvent, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStorySceneEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStorySceneEvent.kt index c4c47a47c..3b2b46d9f 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStorySceneEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStorySceneEvent.kt @@ -49,7 +49,7 @@ class InteractiveStorySceneEvent( fun createAddressTag( pubKey: HexKey, dtag: String, - ): String = ATag.assembleATag(KIND, pubKey, dtag) + ): String = ATag.assembleATagId(KIND, pubKey, dtag) fun create( baseId: String, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt index 3c653b7fc..dd805b2c3 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.quartz.nip01Core.core import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.HexKey import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag @Immutable open class BaseAddressableEvent( @@ -43,5 +43,5 @@ open class BaseAddressableEvent( /** * Creates the tag in a memory efficient way (without creating the ATag class */ - override fun addressTag() = ATag.assembleATag(kind, pubKey, dTag()) + override fun addressTag() = ATag.assembleATagId(kind, pubKey, dTag()) } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt new file mode 100644 index 000000000..0968f210e --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip01Core.core + +import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.HexKey +import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag + +@Immutable +open class BaseReplaceableEvent( + id: HexKey, + pubKey: HexKey, + createdAt: Long, + kind: Int, + tags: TagArray, + content: String, + sig: HexKey, +) : BaseAddressableEvent(id, pubKey, createdAt, kind, tags, content, sig) { + override fun dTag() = FIXED_D_TAG + + override fun address(relayHint: String?) = ATag(kind, pubKey, FIXED_D_TAG, relayHint) + + /** + * Creates the tag in a memory efficient way (without creating the ATag class + */ + override fun addressTag() = ATag.assembleATagId(kind, pubKey, FIXED_D_TAG) + + companion object { + const val FIXED_D_TAG = "" + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/addressables/ATag.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/addressables/ATag.kt index e55815550..2752f1914 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/addressables/ATag.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/addressables/ATag.kt @@ -20,7 +20,11 @@ */ package com.vitorpamplona.quartz.nip01Core.tags.addressables +import android.util.Log import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.HexKey +import com.vitorpamplona.quartz.utils.Hex +import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.pointerSizeInBytes import com.vitorpamplona.quartz.utils.removeTrailingNullsAndEmptyOthers @@ -35,7 +39,7 @@ data class ATag( constructor( kind: Int, - pubKeyHex: String, + pubKeyHex: HexKey, dTag: String, relayHint: String?, ) : this(kind, pubKeyHex, dTag) { @@ -49,17 +53,56 @@ data class ATag( dTag.bytesUsedInMemory() + (relay?.bytesUsedInMemory() ?: 0) - fun toTag() = assembleATag(kind, pubKeyHex, dTag) + fun toTag() = assembleATagId(kind, pubKeyHex, dTag) - fun toATagArray() = removeTrailingNullsAndEmptyOthers("a", toTag(), relay) + fun toATagArray() = removeTrailingNullsAndEmptyOthers(TAG_NAME, toTag(), relay) fun toQTagArray() = removeTrailingNullsAndEmptyOthers("q", toTag(), relay) companion object { - fun assembleATag( + const val TAG_NAME = "a" + + fun assembleATagId( + kind: Int, + pubKeyHex: HexKey, + dTag: String, + ) = "$kind:$pubKeyHex:$dTag" + + fun parse( + aTagId: String, + relay: String?, + ): ATag? = + try { + val parts = aTagId.split(":", limit = 3) + if (Hex.isHex(parts[1])) { + ATag(parts[0].toInt(), parts[1], parts[2], relay) + } else { + Log.w("ATag", "Error parsing A Tag. Pubkey is not hex: $aTagId") + null + } + } catch (t: Throwable) { + Log.w("ATag", "Error parsing A Tag: $aTagId: ${t.message}") + null + } + + @JvmStatic + fun parse(tags: Array): ATag? { + require(tags[0] == TAG_NAME) + return parse(tags[1], tags.getOrNull(2)) + } + + @JvmStatic + fun assemble( + aTagId: HexKey, + relay: String?, + ) = arrayOfNotNull(TAG_NAME, aTagId, relay) + + @JvmStatic + fun assemble( kind: Int, pubKeyHex: String, dTag: String, - ) = "$kind:$pubKeyHex:$dTag" + relay: String?, + ) = arrayOfNotNull(TAG_NAME, assembleATagId(kind, pubKeyHex, dTag), relay) } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayExt.kt index 4a43fff14..00da4d1d5 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayExt.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayExt.kt @@ -28,35 +28,33 @@ import com.vitorpamplona.quartz.nip01Core.core.mapTagged import com.vitorpamplona.quartz.nip01Core.core.mapValueTagged import com.vitorpamplona.quartz.nip19Bech32.parse -fun TagArray.dTag() = this.firstOrNull { it.size > 1 && it[0] == "d" }?.get(1) ?: "" - -fun TagArray.mapTaggedAddress(map: (address: String) -> R) = this.mapValueTagged("a", map) +fun TagArray.mapTaggedAddress(map: (address: String) -> R) = this.mapValueTagged(ATag.TAG_NAME, map) fun TagArray.firstIsTaggedAddressableNote(addressableNotes: Set) = this - .firstOrNull { it.size > 1 && it[0] == "a" && it[1] in addressableNotes } + .firstOrNull { it.size > 1 && it[0] == ATag.TAG_NAME && it[1] in addressableNotes } ?.getOrNull(1) -fun TagArray.isTaggedAddressableNote(idHex: String) = this.isTagged("a", idHex) +fun TagArray.isTaggedAddressableNote(idHex: String) = this.isTagged(ATag.TAG_NAME, idHex) -fun TagArray.isTaggedAddressableNotes(idHexes: Set) = this.isAnyTagged("a", idHexes) +fun TagArray.isTaggedAddressableNotes(idHexes: Set) = this.isAnyTagged(ATag.TAG_NAME, idHexes) fun TagArray.isTaggedAddressableKind(kind: Int): Boolean { val kindStr = kind.toString() - return this.any { it.size > 1 && it[0] == "a" && it[1].startsWith(kindStr) } + return this.any { it.size > 1 && it[0] == ATag.TAG_NAME && it[1].startsWith(kindStr) } } fun TagArray.getTagOfAddressableKind(kind: Int): ATag? { val kindStr = kind.toString() val aTag = this - .firstOrNull { it.size > 1 && it[0] == "a" && it[1].startsWith(kindStr) } + .firstOrNull { it.size > 1 && it[0] == ATag.TAG_NAME && it[1].startsWith(kindStr) } ?.getOrNull(1) ?: return null return ATag.parse(aTag, null) } -fun TagArray.taggedAddresses() = this.mapTagged("a") { ATag.parse(it[1], it.getOrNull(2)) } +fun TagArray.taggedAddresses() = this.mapTagged(ATag.TAG_NAME) { ATag.parse(it) } -fun TagArray.firstTaggedAddress() = this.firstMapTagged("a") { ATag.parse(it[1], it.getOrNull(2)) } +fun TagArray.firstTaggedAddress() = this.firstMapTagged(ATag.TAG_NAME) { ATag.parse(it) } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/DTag.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/DTag.kt new file mode 100644 index 000000000..b5d6a3a6a --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/DTag.kt @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip01Core.tags.dTags + +import com.vitorpamplona.quartz.utils.bytesUsedInMemory +import com.vitorpamplona.quartz.utils.pointerSizeInBytes + +class DTag( + val dId: String, +) { + fun countMemory(): Long = 1 * pointerSizeInBytes + dId.bytesUsedInMemory() + + fun toTagArray() = assemble(dId) + + companion object { + const val TAG_NAME = "d" + + @JvmStatic + fun parse(tags: Array): DTag { + require(tags[0] == TAG_NAME) + return DTag(tags[1]) + } + + @JvmStatic + fun assemble(dId: String) = arrayOf(TAG_NAME, dId) + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/EventExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/EventExt.kt new file mode 100644 index 000000000..4c5035d49 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/EventExt.kt @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip01Core.tags.dTags + +import com.vitorpamplona.quartz.nip01Core.core.Event + +fun Event.dTag() = tags.dTag() diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayBuilderExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayBuilderExt.kt new file mode 100644 index 000000000..96fc5e73b --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayBuilderExt.kt @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip01Core.tags.dTags + +import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder + +fun TagArrayBuilder.dTag(name: String) = add(DTag.assemble(name)) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayExt.kt new file mode 100644 index 000000000..efc7969d0 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayExt.kt @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip01Core.tags.dTags + +import com.vitorpamplona.quartz.nip01Core.core.TagArray +import com.vitorpamplona.quartz.nip01Core.core.firstTagValue + +fun TagArray.dTag() = this.firstTagValue(DTag.TAG_NAME) ?: "" diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip10Notes/ETag.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/events/ETag.kt similarity index 68% rename from quartz/src/main/java/com/vitorpamplona/quartz/nip10Notes/ETag.kt rename to quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/events/ETag.kt index 6c47865f0..10d45bd70 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip10Notes/ETag.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/events/ETag.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.quartz.nip10Notes +package com.vitorpamplona.quartz.nip01Core.tags.events import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.HexKey import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent +import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.pointerSizeInBytes -import com.vitorpamplona.quartz.utils.removeTrailingNullsAndEmptyOthers @Immutable data class ETag( @@ -40,13 +40,31 @@ data class ETag( } fun countMemory(): Long = - 2 * pointerSizeInBytes + // 2 fields, 4 bytes each reference (32bit) + 3 * pointerSizeInBytes + // 3 fields, 4 bytes each reference (32bit) eventId.bytesUsedInMemory() + - (relay?.bytesUsedInMemory() ?: 0) + (relay?.bytesUsedInMemory() ?: 0) + + (authorPubKeyHex?.bytesUsedInMemory() ?: 0) fun toNEvent(): String = NEvent.create(eventId, authorPubKeyHex, null, relay) - fun toETagArray() = removeTrailingNullsAndEmptyOthers("e", eventId, relay, authorPubKeyHex) + fun toETagArray() = arrayOfNotNull(TAG_NAME, eventId, relay, authorPubKeyHex) - fun toQTagArray() = removeTrailingNullsAndEmptyOthers("q", eventId, relay, authorPubKeyHex) + fun toQTagArray() = arrayOfNotNull("q", eventId, relay, authorPubKeyHex) + + companion object { + const val TAG_NAME = "e" + + @JvmStatic + fun parse(tags: Array): ETag { + require(tags[0] == TAG_NAME) + return ETag(tags[1], tags.getOrNull(2), tags.getOrNull(3)) + } + + @JvmStatic + fun assemble( + eventId: HexKey, + relay: String?, + author: HexKey?, + ) = arrayOfNotNull(TAG_NAME, eventId, relay, author) + } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/events/EventExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/events/EventExt.kt index 1a71c83e4..eea195ef9 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/events/EventExt.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/events/EventExt.kt @@ -23,12 +23,14 @@ package com.vitorpamplona.quartz.nip01Core.tags.events import com.vitorpamplona.quartz.nip01Core.HexKey import com.vitorpamplona.quartz.nip01Core.core.Event -fun Event.forEachTaggedEvent(onEach: (eventId: HexKey) -> Unit) = tags.forEachTaggedEvent(onEach) +fun Event.forEachTaggedEventId(onEach: (eventId: HexKey) -> Unit) = tags.forEachTaggedEventId(onEach) -fun Event.mapTaggedEvent(map: (eventId: HexKey) -> R) = tags.mapTaggedEvent(map) +fun Event.mapTaggedEventId(map: (eventId: HexKey) -> R) = tags.mapTaggedEventId(map) fun Event.taggedEvents() = tags.taggedEvents() +fun Event.taggedEventIds() = tags.taggedEventIds() + fun Event.firstTaggedEvent() = tags.firstTaggedEvent() fun Event.isTaggedEvent(idHex: String) = tags.isTaggedEvent(idHex) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayExt.kt index c5c6f6917..5010c44c2 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayExt.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayExt.kt @@ -22,18 +22,22 @@ package com.vitorpamplona.quartz.nip01Core.tags.events import com.vitorpamplona.quartz.nip01Core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArray -import com.vitorpamplona.quartz.nip01Core.core.firstTagValue +import com.vitorpamplona.quartz.nip01Core.core.firstMapTagged import com.vitorpamplona.quartz.nip01Core.core.forEachTagged import com.vitorpamplona.quartz.nip01Core.core.isTagged +import com.vitorpamplona.quartz.nip01Core.core.mapTagged import com.vitorpamplona.quartz.nip01Core.core.mapValueTagged import com.vitorpamplona.quartz.nip01Core.core.mapValues +import com.vitorpamplona.quartz.nip19Bech32.parse -fun TagArray.forEachTaggedEvent(onEach: (eventId: HexKey) -> Unit) = this.forEachTagged("e", onEach) +fun TagArray.forEachTaggedEventId(onEach: (eventId: HexKey) -> Unit) = this.forEachTagged(ETag.TAG_NAME, onEach) -fun TagArray.mapTaggedEvent(map: (eventId: HexKey) -> R) = this.mapValueTagged("e", map) +fun TagArray.mapTaggedEventId(map: (eventId: HexKey) -> R) = this.mapValueTagged(ETag.TAG_NAME, map) -fun TagArray.taggedEvents() = this.mapValues("e") +fun TagArray.taggedEvents() = this.mapTagged(ETag.TAG_NAME) { ETag.parse(it) } -fun TagArray.firstTaggedEvent() = this.firstTagValue("e") +fun TagArray.taggedEventIds() = this.mapValues(ETag.TAG_NAME) -fun TagArray.isTaggedEvent(idHex: String) = this.isTagged("e", idHex) +fun TagArray.firstTaggedEvent() = this.firstMapTagged(ETag.TAG_NAME) { ETag.parse(it) } + +fun TagArray.isTaggedEvent(idHex: String) = this.isTagged(ETag.TAG_NAME, idHex) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt index 024d0262e..2bf285381 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt @@ -26,6 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.tags.addressables.taggedAddresses +import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEventIds import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents import com.vitorpamplona.quartz.nip31Alts.AltTagSerializer import com.vitorpamplona.quartz.utils.TimeUtils @@ -41,6 +42,8 @@ class DeletionEvent( ) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { fun deleteEvents() = taggedEvents() + fun deleteEventIds() = taggedEventIds() + fun deleteAddresses() = taggedAddresses() fun deleteAddressTags() = tags.mapNotNull { if (it.size > 1 && it[0] == "a") it[1] else null } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip13Pow/PoWTag.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip13Pow/PoWTag.kt index 0188991cd..c56efad21 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip13Pow/PoWTag.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip13Pow/PoWTag.kt @@ -33,7 +33,7 @@ class PoWTag( fun toTagArray() = assemble(nonce, commitment) companion object { - val TAG_NAME = "nonce" + const val TAG_NAME = "nonce" @JvmStatic fun parse(tags: Array): PoWTag { diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip14Subject/SubjectTag.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip14Subject/SubjectTag.kt index fc6a3f50f..5baf21f0a 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip14Subject/SubjectTag.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip14Subject/SubjectTag.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.quartz.nip14Subject +import com.vitorpamplona.quartz.nip01Core.tags.dTags.DTag import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.pointerSizeInBytes @@ -31,12 +32,12 @@ class SubjectTag( fun toTagArray() = assemble(subject) companion object { - val TAG_NAME = "subject" + const val TAG_NAME = "subject" @JvmStatic - fun parse(tags: Array): SubjectTag { + fun parse(tags: Array): DTag { require(tags[0] == TAG_NAME) - return SubjectTag(tags[1]) + return DTag(tags[1]) } @JvmStatic diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip17Dm/ChatMessageRelayListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip17Dm/ChatMessageRelayListEvent.kt index b3f5cbc77..8b0993421 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip17Dm/ChatMessageRelayListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip17Dm/ChatMessageRelayListEvent.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.nip17Dm import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent +import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag @@ -37,9 +37,7 @@ class ChatMessageRelayListEvent( tags: Array>, content: String, sig: HexKey, -) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { - override fun dTag() = FIXED_D_TAG - +) : BaseReplaceableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { fun relays(): List = tags.mapNotNull { if (it.size > 1 && it[0] == "relay") { @@ -51,11 +49,10 @@ class ChatMessageRelayListEvent( companion object { const val KIND = 10050 - const val FIXED_D_TAG = "" fun createAddressATag(pubKey: HexKey): ATag = ATag(KIND, pubKey, FIXED_D_TAG, null) - fun createAddressTag(pubKey: HexKey): String = ATag.assembleATag(KIND, pubKey, FIXED_D_TAG) + fun createAddressTag(pubKey: HexKey): String = ATag.assembleATagId(KIND, pubKey, FIXED_D_TAG) fun createTagArray(relays: List): Array> = relays diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip19Bech32/entities/NAddress.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip19Bech32/entities/NAddress.kt index e5627fd9d..ed507b003 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip19Bech32/entities/NAddress.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip19Bech32/entities/NAddress.kt @@ -40,7 +40,7 @@ data class NAddress( val dTag: String, val relay: List, ) : Entity { - fun aTag(): String = ATag.assembleATag(kind, author, dTag) + fun aTag(): String = ATag.assembleATagId(kind, author, dTag) companion object { fun parse(naddr: String): NAddress? { diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip22Comments/CommentEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip22Comments/CommentEvent.kt index 34fa19ccd..1f56efc18 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip22Comments/CommentEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip22Comments/CommentEvent.kt @@ -27,10 +27,10 @@ import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.geohash.geohashMipMap import com.vitorpamplona.quartz.nip01Core.tags.hashtags.buildHashtagTags import com.vitorpamplona.quartz.nip10Notes.BaseTextNoteEvent -import com.vitorpamplona.quartz.nip10Notes.ETag import com.vitorpamplona.quartz.nip10Notes.PTag import com.vitorpamplona.quartz.nip10Notes.content.buildUrlRefs import com.vitorpamplona.quartz.nip10Notes.content.findHashtags diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt index 9f3a07cc4..38dc910b9 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt @@ -25,7 +25,7 @@ import com.vitorpamplona.quartz.nip01Core.HexKey import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags import com.vitorpamplona.quartz.nip10Notes.BaseTextNoteEvent import com.vitorpamplona.quartz.nip31Alts.AltTagSerializer @@ -45,7 +45,7 @@ class LongTextNoteEvent( override fun address(relayHint: String?) = ATag(kind, pubKey, dTag(), relayHint) - override fun addressTag() = ATag.assembleATag(kind, pubKey, dTag()) + override fun addressTag() = ATag.assembleATagId(kind, pubKey, dTag()) fun topics() = hashtags() diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip28PublicChat/ChannelListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip28PublicChat/ChannelListEvent.kt index dc689c09d..4eef28c7d 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip28PublicChat/ChannelListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip28PublicChat/ChannelListEvent.kt @@ -45,8 +45,6 @@ class ChannelListEvent( super.countMemory() + 32 + (publicAndPrivateEventCache?.sumOf { pointerSizeInBytes + it.bytesUsedInMemory() } ?: 0L) // rough calculation - override fun dTag() = FIXED_D_TAG - fun publicAndPrivateEvents( signer: NostrSigner, onReady: (ImmutableSet) -> Unit, @@ -67,7 +65,6 @@ class ChannelListEvent( companion object { const val KIND = 10005 - const val FIXED_D_TAG = "" const val ALT = "Public Chat List" fun blockListFor(pubKeyHex: HexKey): String = "$KIND:$pubKeyHex:" diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip30CustomEmoji/EmojiPackSelectionEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip30CustomEmoji/EmojiPackSelectionEvent.kt index b670eca9a..9a223590b 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip30CustomEmoji/EmojiPackSelectionEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip30CustomEmoji/EmojiPackSelectionEvent.kt @@ -22,11 +22,10 @@ package com.vitorpamplona.quartz.nip30CustomEmoji import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent +import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag import com.vitorpamplona.quartz.nip31Alts.AltTagSerializer -import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent import com.vitorpamplona.quartz.utils.TimeUtils @Immutable @@ -37,28 +36,14 @@ class EmojiPackSelectionEvent( tags: Array>, content: String, sig: HexKey, -) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { - override fun dTag() = FIXED_D_TAG - +) : BaseReplaceableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { companion object { const val KIND = 10030 - const val FIXED_D_TAG = "" const val ALT = "Emoji selection" - fun createAddressATag(pubKey: HexKey): ATag = - ATag( - KIND, - pubKey, - AdvertisedRelayListEvent.FIXED_D_TAG, - null, - ) + fun createAddressATag(pubKey: HexKey) = ATag(KIND, pubKey, FIXED_D_TAG, null) - fun createAddressTag(pubKey: HexKey): String = - ATag.assembleATag( - KIND, - pubKey, - AdvertisedRelayListEvent.FIXED_D_TAG, - ) + fun createAddressTag(pubKey: HexKey) = ATag.assembleATagId(KIND, pubKey, FIXED_D_TAG) fun create( listOfEmojiPacks: List?, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip37Drafts/DraftEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip37Drafts/DraftEvent.kt index 73ec01d23..a3576c6f8 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip37Drafts/DraftEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip37Drafts/DraftEvent.kt @@ -125,7 +125,7 @@ class DraftEvent( fun createAddressTag( pubKey: HexKey, dTag: String, - ): String = ATag.assembleATag(KIND, pubKey, dTag) + ): String = ATag.assembleATagId(KIND, pubKey, dTag) fun create( dTag: String, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip50Search/SearchRelayListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip50Search/SearchRelayListEvent.kt index 93eec3527..c84f395f3 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip50Search/SearchRelayListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip50Search/SearchRelayListEvent.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.nip50Search import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent +import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag @@ -37,9 +37,7 @@ class SearchRelayListEvent( tags: Array>, content: String, sig: HexKey, -) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { - override fun dTag() = FIXED_D_TAG - +) : BaseReplaceableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { fun relays(): List = tags.mapNotNull { if (it.size > 1 && it[0] == "relay") { @@ -51,11 +49,10 @@ class SearchRelayListEvent( companion object { const val KIND = 10007 - const val FIXED_D_TAG = "" fun createAddressATag(pubKey: HexKey): ATag = ATag(KIND, pubKey, FIXED_D_TAG, null) - fun createAddressTag(pubKey: HexKey): String = ATag.assembleATag(KIND, pubKey, FIXED_D_TAG) + fun createAddressTag(pubKey: HexKey): String = ATag.assembleATagId(KIND, pubKey, FIXED_D_TAG) fun createTagArray(relays: List): Array> = relays diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip51Lists/GeneralListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip51Lists/GeneralListEvent.kt index bf8777941..1d4554054 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip51Lists/GeneralListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip51Lists/GeneralListEvent.kt @@ -29,7 +29,6 @@ import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents import com.vitorpamplona.quartz.nip01Core.tags.geohash.geohashes import com.vitorpamplona.quartz.nip01Core.tags.people.taggedUsers -import com.vitorpamplona.quartz.nip19Bech32.parse import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.toImmutableSet diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip51Lists/MuteListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip51Lists/MuteListEvent.kt index 0cf6478d1..b758d1c58 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip51Lists/MuteListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip51Lists/MuteListEvent.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.quartz.nip51Lists import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent.Companion.FIXED_D_TAG import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip31Alts.AltTagSerializer import com.vitorpamplona.quartz.utils.TimeUtils @@ -76,7 +77,6 @@ class MuteListEvent( companion object { const val KIND = 10000 - const val FIXED_D_TAG = "" const val ALT = "Mute List" fun blockListFor(pubKeyHex: HexKey): String = "10000:$pubKeyHex:" diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt index 3103185ab..5369c1195 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt @@ -44,7 +44,7 @@ class WikiNoteEvent( override fun address(relayHint: String?) = ATag(kind, pubKey, dTag(), relayHint) - override fun addressTag() = ATag.assembleATag(kind, pubKey, dTag()) + override fun addressTag() = ATag.assembleATagId(kind, pubKey, dTag()) fun topics() = hashtags() diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip65RelayList/AdvertisedRelayListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip65RelayList/AdvertisedRelayListEvent.kt index 7f7047747..323ed575a 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip65RelayList/AdvertisedRelayListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip65RelayList/AdvertisedRelayListEvent.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.nip65RelayList import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent +import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag @@ -37,9 +37,7 @@ class AdvertisedRelayListEvent( tags: Array>, content: String, sig: HexKey, -) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { - override fun dTag() = FIXED_D_TAG - +) : BaseReplaceableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { fun relays(): List = tags.mapNotNull { if (it.size > 1 && it[0] == "r") { @@ -85,12 +83,11 @@ class AdvertisedRelayListEvent( companion object { const val KIND = 10002 - const val FIXED_D_TAG = "" const val ALT = "Relay list to discover the user's content" fun createAddressATag(pubKey: HexKey): ATag = ATag(KIND, pubKey, FIXED_D_TAG, null) - fun createAddressTag(pubKey: HexKey): String = ATag.assembleATag(KIND, pubKey, FIXED_D_TAG) + fun createAddressTag(pubKey: HexKey): String = ATag.assembleATagId(KIND, pubKey, FIXED_D_TAG) fun updateRelayList( earlierVersion: AdvertisedRelayListEvent, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip68Picture/PictureEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip68Picture/PictureEvent.kt index 48ca9113c..6654fa9b2 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip68Picture/PictureEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip68Picture/PictureEvent.kt @@ -25,9 +25,9 @@ import com.vitorpamplona.quartz.nip01Core.HexKey import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.geohash.geohashMipMap import com.vitorpamplona.quartz.nip01Core.tags.hashtags.buildHashtagTags -import com.vitorpamplona.quartz.nip10Notes.ETag import com.vitorpamplona.quartz.nip10Notes.PTag import com.vitorpamplona.quartz.nip10Notes.content.buildUrlRefs import com.vitorpamplona.quartz.nip10Notes.content.findHashtags diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip72ModCommunities/CommunityListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip72ModCommunities/CommunityListEvent.kt index 29d73ae37..2e8c7a3fd 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip72ModCommunities/CommunityListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip72ModCommunities/CommunityListEvent.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.quartz.nip72ModCommunities import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent.Companion.FIXED_D_TAG import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag import com.vitorpamplona.quartz.nip19Bech32.parseAtag @@ -72,7 +73,6 @@ class CommunityListEvent( companion object { const val KIND = 10004 - const val FIXED_D_TAG = "" const val ALT = "Community List" fun blockListFor(pubKeyHex: HexKey): String = "$KIND:$pubKeyHex:" diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip89AppHandlers/AppRecommendationEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip89AppHandlers/AppRecommendationEvent.kt index 9cc157e28..1c24f0314 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip89AppHandlers/AppRecommendationEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip89AppHandlers/AppRecommendationEvent.kt @@ -25,7 +25,6 @@ import com.vitorpamplona.quartz.nip01Core.HexKey import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip19Bech32.parse import com.vitorpamplona.quartz.nip31Alts.AltTagSerializer import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip96FileStorage/FileServersEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip96FileStorage/FileServersEvent.kt index 0c36a8783..242a7f1e6 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip96FileStorage/FileServersEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip96FileStorage/FileServersEvent.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.nip96FileStorage import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent +import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag import com.vitorpamplona.quartz.nip31Alts.AltTagSerializer @@ -36,9 +36,7 @@ class FileServersEvent( tags: Array>, content: String, sig: HexKey, -) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { - override fun dTag() = FIXED_D_TAG - +) : BaseReplaceableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { fun servers(): List = tags.mapNotNull { if (it.size > 1 && it[0] == "server") { @@ -50,12 +48,11 @@ class FileServersEvent( companion object { const val KIND = 10096 - const val FIXED_D_TAG = "" const val ALT = "File servers used by the author" fun createAddressATag(pubKey: HexKey): ATag = ATag(KIND, pubKey, FIXED_D_TAG, null) - fun createAddressTag(pubKey: HexKey): String = ATag.assembleATag(KIND, pubKey, FIXED_D_TAG) + fun createAddressTag(pubKey: HexKey): String = ATag.assembleATagId(KIND, pubKey, FIXED_D_TAG) fun createTagArray(servers: List): Array> = servers