feat: migrate BookmarkListEvent from kind 30001 to 10003

Rename the existing BookmarkListEvent (kind 30001) to OldBookmarkListEvent
and create a new BookmarkListEvent with kind 10003 as per the updated spec.

- OldBookmarkListEvent (kind 30001): Kept as-is for backward compatibility,
  displayed as "Old Bookmarks" in the Bookmark Lists screen
- BookmarkListEvent (kind 10003): New replaceable event, all new bookmark
  operations (save/check/remove) use this kind
- Both kinds are displayed as separate items in the Bookmark Lists screen
- Old Bookmarks screen includes a "Move All to New Bookmarks" button that
  migrates public bookmarks to public and private to private
- Created PrivateReplaceableTagArrayEvent base class for replaceable events
  with encrypted private tags (kind 10003 is in the 10000-19999 range)
- Updated all relay filters, search queries, and profile views to fetch
  both kinds
- Updated Android and Desktop modules

https://claude.ai/code/session_01U9sjQHQMVVHxYiesoXjqop
This commit is contained in:
Claude
2026-03-31 02:08:54 +00:00
parent 4256e3f3cf
commit b960a4692a
29 changed files with 1013 additions and 24 deletions
@@ -45,6 +45,7 @@ import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent
import com.vitorpamplona.quartz.nip47WalletConnect.events.LnZapPaymentRequestEvent
import com.vitorpamplona.quartz.nip47WalletConnect.events.LnZapPaymentResponseEvent
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.OldBookmarkListEvent
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
import com.vitorpamplona.quartz.utils.DualCase
@@ -213,6 +214,10 @@ class DesktopLocalCache : ICacheProvider {
consumeBookmarkList(event)
}
is OldBookmarkListEvent -> {
consumeOldBookmarkList(event)
}
is CommentEvent -> {
consumeComment(event, relay)
}
@@ -419,6 +424,19 @@ class DesktopLocalCache : ICacheProvider {
return true
}
private fun consumeOldBookmarkList(event: OldBookmarkListEvent): Boolean {
val address = event.address()
val addressableNote = getOrCreateAddressableNote(address)
val author = getOrCreateUser(event.pubKey)
// Only update if newer
val existingEvent = addressableNote.event
if (existingEvent != null && existingEvent.createdAt >= event.createdAt) return false
addressableNote.loadEvent(event, author, emptyList())
return true
}
// ----- NWC Payment operations -----
/**
@@ -27,6 +27,7 @@ import com.vitorpamplona.amethyst.commons.model.User
import com.vitorpamplona.amethyst.commons.model.nip02FollowList.Kind3FollowListRepository
import com.vitorpamplona.amethyst.commons.model.nip02FollowList.Kind3FollowListState
import com.vitorpamplona.amethyst.commons.model.nip51Lists.BookmarkListState
import com.vitorpamplona.amethyst.commons.model.nip51Lists.OldBookmarkListState
import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListRepository
import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState
import com.vitorpamplona.amethyst.commons.model.privateChats.ChatroomList
@@ -76,6 +77,7 @@ class DesktopIAccount(
// ----- State Classes (pin important notes via strong refs for GC retention) -----
val oldBookmarkState = OldBookmarkListState(signer, localCache, scope)
val bookmarkState = BookmarkListState(signer, localCache, scope)
val kind3FollowList =
@@ -37,6 +37,7 @@ import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelMetadataEvent
import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent
import com.vitorpamplona.quartz.nip51Lists.PinListEvent
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.OldBookmarkListEvent
import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent
import com.vitorpamplona.quartz.nip51Lists.peopleList.PeopleListEvent
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent
@@ -58,6 +59,7 @@ object SearchFilterFactory {
BadgeDefinitionEvent.KIND,
PeopleListEvent.KIND,
BookmarkListEvent.KIND,
OldBookmarkListEvent.KIND,
AudioHeaderEvent.KIND,
AudioTrackEvent.KIND,
PinListEvent.KIND,