- Removes the deprecated hacks from Contact Lists

- Removes the use of kind 3 to show hashtags which fixes issues when people unfollowing the hashtag and it would just affect the InterestListEvent
This commit is contained in:
Vitor Pamplona
2025-10-22 18:31:00 -04:00
parent 2d551d4adf
commit ee80361478
11 changed files with 69 additions and 86 deletions
@@ -38,8 +38,8 @@ import com.vitorpamplona.amethyst.model.nip01UserMetadata.UserMetadataState
import com.vitorpamplona.amethyst.model.nip02FollowLists.DeclaredFollowsPerOutboxRelay import com.vitorpamplona.amethyst.model.nip02FollowLists.DeclaredFollowsPerOutboxRelay
import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListOutboxOrProxyRelays import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListOutboxOrProxyRelays
import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListReusedOutboxOrProxyRelays import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListReusedOutboxOrProxyRelays
import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListState
import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowsPerOutboxRelay import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowsPerOutboxRelay
import com.vitorpamplona.amethyst.model.nip02FollowLists.Kind3FollowListState
import com.vitorpamplona.amethyst.model.nip03Timestamp.OtsState import com.vitorpamplona.amethyst.model.nip03Timestamp.OtsState
import com.vitorpamplona.amethyst.model.nip17Dms.DmInboxRelayState import com.vitorpamplona.amethyst.model.nip17Dms.DmInboxRelayState
import com.vitorpamplona.amethyst.model.nip17Dms.DmRelayListState import com.vitorpamplona.amethyst.model.nip17Dms.DmRelayListState
@@ -266,7 +266,7 @@ class Account(
val blockedRelayListDecryptionCache = BlockedRelayListDecryptionCache(signer) val blockedRelayListDecryptionCache = BlockedRelayListDecryptionCache(signer)
val blockedRelayList = BlockedRelayListState(signer, cache, blockedRelayListDecryptionCache, scope, settings) val blockedRelayList = BlockedRelayListState(signer, cache, blockedRelayListDecryptionCache, scope, settings)
val kind3FollowList = FollowListState(signer, cache, scope, settings) val kind3FollowList = Kind3FollowListState(signer, cache, scope, settings)
val followSetsState = FollowSetState(signer, cache, scope) val followSetsState = FollowSetState(signer, cache, scope)
val ephemeralChatListDecryptionCache = EphemeralChatListDecryptionCache(signer) val ephemeralChatListDecryptionCache = EphemeralChatListDecryptionCache(signer)
@@ -37,7 +37,7 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.flow.transformLatest
class DeclaredFollowsPerOutboxRelay( class DeclaredFollowsPerOutboxRelay(
kind3Follows: FollowListState, kind3Follows: Kind3FollowListState,
val cache: LocalCache, val cache: LocalCache,
scope: CoroutineScope, scope: CoroutineScope,
) { ) {
@@ -42,7 +42,7 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.flow.transformLatest
class FollowListOutboxOrProxyRelays( class FollowListOutboxOrProxyRelays(
kind3Follows: FollowListState, kind3Follows: Kind3FollowListState,
blockedRelayList: BlockedRelayListState, blockedRelayList: BlockedRelayListState,
proxyRelayList: ProxyRelayListState, proxyRelayList: ProxyRelayListState,
val cache: LocalCache, val cache: LocalCache,
@@ -42,7 +42,7 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.flow.transformLatest
class FollowListReusedOutboxOrProxyRelays( class FollowListReusedOutboxOrProxyRelays(
kind3Follows: FollowListState, kind3Follows: Kind3FollowListState,
blockedRelayList: BlockedRelayListState, blockedRelayList: BlockedRelayListState,
proxyRelayList: ProxyRelayListState, proxyRelayList: ProxyRelayListState,
val cache: LocalCache, val cache: LocalCache,
@@ -42,7 +42,7 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.flow.transformLatest
class FollowsPerOutboxRelay( class FollowsPerOutboxRelay(
kind3Follows: FollowListState, kind3Follows: Kind3FollowListState,
blockedRelayList: BlockedRelayListState, blockedRelayList: BlockedRelayListState,
proxyRelayList: ProxyRelayListState, proxyRelayList: ProxyRelayListState,
val cache: LocalCache, val cache: LocalCache,
@@ -25,12 +25,10 @@ import com.vitorpamplona.amethyst.model.AccountSettings
import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.model.UserState import com.vitorpamplona.amethyst.model.UserState
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
import com.vitorpamplona.quartz.nip01Core.tags.geohash.geohashes
import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent
import com.vitorpamplona.quartz.nip02FollowList.tags.ContactTag import com.vitorpamplona.quartz.nip02FollowList.tags.ContactTag
import com.vitorpamplona.quartz.nip73ExternalIds.location.GeohashId
import com.vitorpamplona.quartz.nip73ExternalIds.topics.HashtagId
import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.Log
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.DelicateCoroutinesApi
@@ -45,7 +43,7 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class FollowListState( class Kind3FollowListState(
val signer: NostrSigner, val signer: NostrSigner,
val cache: LocalCache, val cache: LocalCache,
val scope: CoroutineScope, val scope: CoroutineScope,
@@ -77,8 +75,8 @@ class FollowListState(
// Creates a long-term reference for all follows of a user // Creates a long-term reference for all follows of a user
val userList = val userList =
flow flow
.map { .map { kind3Follows ->
it.authors.mapNotNull { kind3Follows.authors.mapNotNull {
cache.checkGetOrCreateUser(it) cache.checkGetOrCreateUser(it)
} }
}.flowOn(Dispatchers.IO) }.flowOn(Dispatchers.IO)
@@ -96,15 +94,9 @@ class FollowListState(
*/ */
@Immutable @Immutable
class Kind3Follows( class Kind3Follows(
val authors: Set<String> = emptySet(), val authors: Set<HexKey> = emptySet(),
val authorsPlusMe: Set<String>, val authorsPlusMe: Set<HexKey>,
val hashtags: Set<String> = emptySet(), )
val geotags: Set<String> = emptySet(),
val communities: Set<String> = emptySet(),
) {
val geotagScopes: Set<String> = geotags.mapTo(mutableSetOf<String>()) { GeohashId.toScope(it) }
val hashtagScopes: Set<String> = hashtags.mapTo(mutableSetOf<String>()) { HashtagId.toScope(it) }
}
fun buildKind3Follows(latestContactList: ContactListEvent?): Kind3Follows { fun buildKind3Follows(latestContactList: ContactListEvent?): Kind3Follows {
// makes sure the output include only valid p tags // makes sure the output include only valid p tags
@@ -113,19 +105,6 @@ class FollowListState(
return Kind3Follows( return Kind3Follows(
authors = verifiedFollowingUsers, authors = verifiedFollowingUsers,
authorsPlusMe = verifiedFollowingUsers + signer.pubKey, authorsPlusMe = verifiedFollowingUsers + signer.pubKey,
hashtags =
latestContactList
?.unverifiedFollowTagSet()
?.map { it.lowercase() }
?.toSet() ?: emptySet(),
geotags =
latestContactList
?.geohashes()
?.toSet() ?: emptySet(),
communities =
latestContactList
?.verifiedFollowAddressSet()
?.toSet() ?: emptySet(),
) )
} }
@@ -20,12 +20,15 @@
*/ */
package com.vitorpamplona.amethyst.model.serverList package com.vitorpamplona.amethyst.model.serverList
import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListState import androidx.compose.runtime.Immutable
import com.vitorpamplona.amethyst.model.nip02FollowLists.Kind3FollowListState
import com.vitorpamplona.amethyst.model.nip51Lists.followSets.FollowSetState import com.vitorpamplona.amethyst.model.nip51Lists.followSets.FollowSetState
import com.vitorpamplona.amethyst.model.nip51Lists.geohashLists.GeohashListState import com.vitorpamplona.amethyst.model.nip51Lists.geohashLists.GeohashListState
import com.vitorpamplona.amethyst.model.nip51Lists.hashtagLists.HashtagListState import com.vitorpamplona.amethyst.model.nip51Lists.hashtagLists.HashtagListState
import com.vitorpamplona.amethyst.model.nip72Communities.CommunityListState import com.vitorpamplona.amethyst.model.nip72Communities.CommunityListState
import com.vitorpamplona.quartz.nip72ModCommunities.follow.tags.CommunityTag import com.vitorpamplona.quartz.nip72ModCommunities.follow.tags.CommunityTag
import com.vitorpamplona.quartz.nip73ExternalIds.location.GeohashId
import com.vitorpamplona.quartz.nip73ExternalIds.topics.HashtagId
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
@@ -37,38 +40,50 @@ import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
class MergedFollowListsState( class MergedFollowListsState(
val kind3List: FollowListState, val kind3List: Kind3FollowListState,
val followSetList: FollowSetState, val followSetList: FollowSetState,
val hashtagList: HashtagListState, val hashtagList: HashtagListState,
val geohashList: GeohashListState, val geohashList: GeohashListState,
val communityList: CommunityListState, val communityList: CommunityListState,
val scope: CoroutineScope, val scope: CoroutineScope,
) { ) {
/**
This contains a big OR of everything the user wants to see in the a single feed.
*/
@Immutable
class AllFollows(
val authors: Set<String> = emptySet(),
val hashtags: Set<String> = emptySet(),
val geotags: Set<String> = emptySet(),
val communities: Set<String> = emptySet(),
) {
val geotagScopes: Set<String> = geotags.mapTo(mutableSetOf<String>()) { GeohashId.toScope(it) }
val hashtagScopes: Set<String> = hashtags.mapTo(mutableSetOf<String>()) { HashtagId.toScope(it) }
}
fun mergeLists( fun mergeLists(
kind3: FollowListState.Kind3Follows, kind3: Kind3FollowListState.Kind3Follows,
followSetProfiles: Set<String>, followSetProfiles: Set<String>,
hashtags: Set<String>, hashtags: Set<String>,
geohashes: Set<String>, geohashes: Set<String>,
community: Set<CommunityTag>, community: Set<CommunityTag>,
): FollowListState.Kind3Follows = ): AllFollows =
FollowListState.Kind3Follows( AllFollows(
kind3.authors + followSetProfiles, authors = kind3.authors + followSetProfiles,
kind3.authorsPlusMe, hashtags = hashtags,
kind3.hashtags + hashtags, geotags = geohashes,
kind3.geotags + geohashes, communities = community.mapTo(mutableSetOf()) { it.address.toValue() },
kind3.communities + community.map { it.address.toValue() },
) )
val flow: StateFlow<FollowListState.Kind3Follows> = val flow: StateFlow<AllFollows> =
combine( combine(
kind3List.flow, kind3List.flow,
followSetList.profilesFlow, followSetList.profilesFlow,
hashtagList.flow, hashtagList.flow,
geohashList.flow, geohashList.flow,
communityList.flow, communityList.flow,
) { kind3, followSet, hashtag, geohash, community -> ::mergeLists,
mergeLists(kind3, followSet, hashtag, geohash, community) ).onStart {
}.onStart {
emit( emit(
mergeLists( mergeLists(
kind3List.flow.value, kind3List.flow.value,
@@ -83,6 +98,12 @@ class MergedFollowListsState(
.stateIn( .stateIn(
scope, scope,
SharingStarted.Eagerly, SharingStarted.Eagerly,
mergeLists(
kind3List.flow.value, kind3List.flow.value,
followSetList.profilesFlow.value,
hashtagList.flow.value,
geohashList.flow.value,
communityList.flow.value,
),
) )
} }
@@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.ALL_USER_FOLLOWS
import com.vitorpamplona.amethyst.model.AROUND_ME import com.vitorpamplona.amethyst.model.AROUND_ME
import com.vitorpamplona.amethyst.model.GLOBAL_FOLLOWS import com.vitorpamplona.amethyst.model.GLOBAL_FOLLOWS
import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListState import com.vitorpamplona.amethyst.model.serverList.MergedFollowListsState
import com.vitorpamplona.amethyst.model.topNavFeeds.allFollows.AllFollowsFeedFlow import com.vitorpamplona.amethyst.model.topNavFeeds.allFollows.AllFollowsFeedFlow
import com.vitorpamplona.amethyst.model.topNavFeeds.allUserFollows.AllUserFollowsFeedFlow import com.vitorpamplona.amethyst.model.topNavFeeds.allUserFollows.AllUserFollowsFeedFlow
import com.vitorpamplona.amethyst.model.topNavFeeds.aroundMe.AroundMeFeedFlow import com.vitorpamplona.amethyst.model.topNavFeeds.aroundMe.AroundMeFeedFlow
@@ -49,7 +49,7 @@ import kotlinx.coroutines.flow.transformLatest
class FeedTopNavFilterState( class FeedTopNavFilterState(
val feedFilterListName: MutableStateFlow<String>, val feedFilterListName: MutableStateFlow<String>,
val allFollows: StateFlow<FollowListState.Kind3Follows>, val allFollows: StateFlow<MergedFollowListsState.AllFollows>,
val locationFlow: StateFlow<LocationState.LocationResult>, val locationFlow: StateFlow<LocationState.LocationResult>,
val followsRelays: StateFlow<Set<NormalizedRelayUrl>>, val followsRelays: StateFlow<Set<NormalizedRelayUrl>>,
val blockedRelays: StateFlow<Set<NormalizedRelayUrl>>, val blockedRelays: StateFlow<Set<NormalizedRelayUrl>>,
@@ -20,7 +20,7 @@
*/ */
package com.vitorpamplona.amethyst.model.topNavFeeds.allFollows package com.vitorpamplona.amethyst.model.topNavFeeds.allFollows
import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListState import com.vitorpamplona.amethyst.model.serverList.MergedFollowListsState
import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedFlowsType import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedFlowsType
import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedTopNavFilter
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -29,31 +29,31 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
class AllFollowsFeedFlow( class AllFollowsFeedFlow(
val allFollows: StateFlow<FollowListState.Kind3Follows?>, val allFollows: StateFlow<MergedFollowListsState.AllFollows?>,
val followsRelays: StateFlow<Set<NormalizedRelayUrl>>, val followsRelays: StateFlow<Set<NormalizedRelayUrl>>,
val blockedRelays: StateFlow<Set<NormalizedRelayUrl>>, val blockedRelays: StateFlow<Set<NormalizedRelayUrl>>,
val proxyRelays: StateFlow<Set<NormalizedRelayUrl>>, val proxyRelays: StateFlow<Set<NormalizedRelayUrl>>,
) : IFeedFlowsType { ) : IFeedFlowsType {
fun convert( fun convert(
kind3: FollowListState.Kind3Follows?, allFollows: MergedFollowListsState.AllFollows?,
proxyRelays: Set<NormalizedRelayUrl>, proxyRelays: Set<NormalizedRelayUrl>,
): IFeedTopNavFilter = ): IFeedTopNavFilter =
if (kind3 != null) { if (allFollows != null) {
if (proxyRelays.isEmpty()) { if (proxyRelays.isEmpty()) {
AllFollowsByOutboxTopNavFilter( AllFollowsByOutboxTopNavFilter(
authors = kind3.authors, authors = allFollows.authors,
hashtags = kind3.hashtags, hashtags = allFollows.hashtags,
geotags = kind3.geotags, geotags = allFollows.geotags,
communities = kind3.communities, communities = allFollows.communities,
defaultRelays = followsRelays, defaultRelays = followsRelays,
blockedRelays = blockedRelays, blockedRelays = blockedRelays,
) )
} else { } else {
AllFollowsByProxyTopNavFilter( AllFollowsByProxyTopNavFilter(
authors = kind3.authors, authors = allFollows.authors,
hashtags = kind3.hashtags, hashtags = allFollows.hashtags,
geotags = kind3.geotags, geotags = allFollows.geotags,
communities = kind3.communities, communities = allFollows.communities,
proxyRelays = proxyRelays, proxyRelays = proxyRelays,
) )
} }
@@ -20,7 +20,7 @@
*/ */
package com.vitorpamplona.amethyst.model.topNavFeeds.allUserFollows package com.vitorpamplona.amethyst.model.topNavFeeds.allUserFollows
import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListState import com.vitorpamplona.amethyst.model.serverList.MergedFollowListsState
import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedFlowsType import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedFlowsType
import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedTopNavFilter
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -29,25 +29,25 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
class AllUserFollowsFeedFlow( class AllUserFollowsFeedFlow(
val allFollows: StateFlow<FollowListState.Kind3Follows?>, val allFollows: StateFlow<MergedFollowListsState.AllFollows?>,
val followsRelays: StateFlow<Set<NormalizedRelayUrl>>, val followsRelays: StateFlow<Set<NormalizedRelayUrl>>,
val blockedRelays: StateFlow<Set<NormalizedRelayUrl>>, val blockedRelays: StateFlow<Set<NormalizedRelayUrl>>,
val proxyRelays: StateFlow<Set<NormalizedRelayUrl>>, val proxyRelays: StateFlow<Set<NormalizedRelayUrl>>,
) : IFeedFlowsType { ) : IFeedFlowsType {
fun convert( fun convert(
kind3: FollowListState.Kind3Follows?, allFollows: MergedFollowListsState.AllFollows?,
proxyRelays: Set<NormalizedRelayUrl>, proxyRelays: Set<NormalizedRelayUrl>,
): IFeedTopNavFilter = ): IFeedTopNavFilter =
if (kind3 != null) { if (allFollows != null) {
if (proxyRelays.isEmpty()) { if (proxyRelays.isEmpty()) {
AllUserFollowsByOutboxTopNavFilter( AllUserFollowsByOutboxTopNavFilter(
authors = kind3.authors, authors = allFollows.authors,
defaultRelays = followsRelays, defaultRelays = followsRelays,
blockedRelays = blockedRelays, blockedRelays = blockedRelays,
) )
} else { } else {
AllUserFollowsByProxyTopNavFilter( AllUserFollowsByProxyTopNavFilter(
authors = kind3.authors, authors = allFollows.authors,
proxyRelays = proxyRelays, proxyRelays = proxyRelays,
) )
} }
@@ -23,14 +23,11 @@ package com.vitorpamplona.quartz.nip02FollowList
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider
import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags
import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser
import com.vitorpamplona.quartz.nip02FollowList.tags.ContactTag import com.vitorpamplona.quartz.nip02FollowList.tags.ContactTag
import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.AltTag
@@ -45,12 +42,7 @@ class ContactListEvent(
content: String, content: String,
sig: HexKey, sig: HexKey,
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig), ) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
AddressHintProvider,
PubKeyHintProvider { PubKeyHintProvider {
override fun addressHints() = tags.mapNotNull(ATag::parseAsHint)
override fun linkedAddressIds() = tags.mapNotNull(ATag::parseAddressId)
override fun pubKeyHints() = tags.mapNotNull(ContactTag::parseAsHint) override fun pubKeyHints() = tags.mapNotNull(ContactTag::parseAsHint)
override fun linkedPubKeys() = tags.mapNotNull(ContactTag::parseKey) override fun linkedPubKeys() = tags.mapNotNull(ContactTag::parseKey)
@@ -60,17 +52,8 @@ class ContactListEvent(
*/ */
fun verifiedFollowKeySet(): Set<HexKey> = tags.mapNotNullTo(mutableSetOf(), ContactTag::parseValidKey) fun verifiedFollowKeySet(): Set<HexKey> = tags.mapNotNullTo(mutableSetOf(), ContactTag::parseValidKey)
/**
* Returns a list of a-tags that are verified as correct.
*/
@Deprecated("Use CommunityListEvent instead.")
fun verifiedFollowAddressSet(): Set<HexKey> = tags.mapNotNullTo(mutableSetOf(), ATag::parseValidAddress)
fun unverifiedFollowKeySet() = tags.mapNotNull(ContactTag::parseKey) fun unverifiedFollowKeySet() = tags.mapNotNull(ContactTag::parseKey)
@Deprecated("Use HashtagListEvent instead.")
fun unverifiedFollowTagSet() = tags.hashtags()
fun follows() = tags.mapNotNull(ContactTag::parseValid) fun follows() = tags.mapNotNull(ContactTag::parseValid)
fun relays(): Map<NormalizedRelayUrl, ReadWrite>? { fun relays(): Map<NormalizedRelayUrl, ReadWrite>? {