From b6808959cd82715166bb22725711fb1f4a72db5b Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 30 Jul 2026 20:59:48 -0400 Subject: [PATCH] refactor(relays): split the public-chat purpose into the five protocols it held MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PUBLIC_CHATS was a catch-all carrying NIP-28 chats, NIP-29 relay groups, ephemeral chats, geohash chats and live-stream chat under one row labelled with the NIP-29 name — so the subscription screen could not say where any of them came from, and the label was wrong for four fifths of what it counted. Each is now its own purpose with its own label and explainer. Geohash cells carry their id too, so location chats list one row per cell and render as a place name instead of a single opaque group. Co-Authored-By: Claude Opus 5 (1M context) --- .../FilterGoalForLiveActivity.kt | 4 +- .../FilterMessagesToEphemeralChat.kt | 2 +- .../FilterMessagesToGeohashChat.kt | 5 ++- .../FilterMessagesToLiveStream.kt | 2 +- .../FilterMyMessagesToEphemeralChat.kt | 2 +- .../FilterMyMessagesToLiveActivities.kt | 2 +- .../subassemblies/FilterRelayGroupState.kt | 6 +-- .../RelayGroupCardWarmupFilterAssembler.kt | 7 +-- .../datasource/RelayGroupFilterBuilders.kt | 31 +++++++------ .../FilterRelayGroupsByAuthors.kt | 6 +-- .../FilterRelayGroupsByGeohashes.kt | 2 +- .../FilterRelayGroupsByHashtag.kt | 2 +- .../FilterRelayGroupsDirectory.kt | 2 +- .../FilterFollowingEphemeralChats.kt | 2 +- .../datasource/FilterFollowingGeohashChats.kt | 5 ++- .../relays/common/SubPurposeLabels.kt | 38 +++++++++++----- amethyst/src/main/res/values/strings.xml | 43 +++++++++++++++++-- .../relayClient/subscriptions/SubPurpose.kt | 42 +++++++++++++++++- 18 files changed, 153 insertions(+), 50 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterGoalForLiveActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterGoalForLiveActivity.kt index 212ce98b67..7c55b9db06 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterGoalForLiveActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterGoalForLiveActivity.kt @@ -49,7 +49,7 @@ fun filterGoalForLiveActivities( relay = relay, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.LIVE_CHAT, kinds = listOf(GoalEvent.KIND), ids = listOf(goalId), limit = 1, @@ -59,7 +59,7 @@ fun filterGoalForLiveActivities( relay = relay, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.LIVE_CHAT, kinds = listOf(LnZapEvent.KIND, OnchainZapEvent.KIND, Bolt12ZapEvent.KIND), tags = mapOf("e" to listOf(goalId)), limit = 200, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToEphemeralChat.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToEphemeralChat.kt index 6ba64df397..a3797580b0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToEphemeralChat.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToEphemeralChat.kt @@ -36,7 +36,7 @@ fun filterMessagesToEphemeralChat( relay = it, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.EPHEMERAL_CHATS, kinds = listOf(EphemeralChatEvent.KIND), tags = if (channel.roomId.id.isBlank()) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToGeohashChat.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToGeohashChat.kt index 28bf7a214f..837b6da8e1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToGeohashChat.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToGeohashChat.kt @@ -43,7 +43,10 @@ fun filterMessagesToGeohashChat( relay = it, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.GEOHASH_CHATS, + // The cell IS the chat's identity, so the screen can list one row per location + // instead of collapsing every joined cell into one unnamed entry. + entityIds = listOf(channel.geohash), kinds = listOf(GeohashChatEvent.KIND), tags = mapOf("g" to listOf(channel.geohash)), limit = 200, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToLiveStream.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToLiveStream.kt index bebfa71971..6a5410c356 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToLiveStream.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToLiveStream.kt @@ -41,7 +41,7 @@ fun filterMessagesToLiveActivities( relay = it, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.LIVE_CHAT, kinds = listOf( LiveActivitiesChatMessageEvent.KIND, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMyMessagesToEphemeralChat.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMyMessagesToEphemeralChat.kt index e3511f3cc3..650e55c344 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMyMessagesToEphemeralChat.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMyMessagesToEphemeralChat.kt @@ -38,7 +38,7 @@ fun filterMyMessagesToEphemeralChat( relay = it, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.EPHEMERAL_CHATS, kinds = listOf(EphemeralChatEvent.KIND), tags = if (channel.roomId.id.isBlank()) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMyMessagesToLiveActivities.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMyMessagesToLiveActivities.kt index c9d718ad05..2258d81255 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMyMessagesToLiveActivities.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMyMessagesToLiveActivities.kt @@ -38,7 +38,7 @@ fun filterMyMessagesToLiveActivities( relay = it, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.LIVE_CHAT, kinds = listOf(LiveActivitiesChatMessageEvent.KIND), tags = mapOf("a" to listOfNotNull(channel.address.toValue())), authors = listOf(pubKey), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterRelayGroupState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterRelayGroupState.kt index 15f1a535d1..f56aa7f54f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterRelayGroupState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterRelayGroupState.kt @@ -49,8 +49,8 @@ fun filterRelayGroupState( relays.flatMap { val floor = since?.get(it)?.time listOf( - RelayBasedFilter(relay = it, filter = ExplainedFilter(purpose = SubPurpose.PUBLIC_CHATS, kinds = RELAY_GROUP_METADATA_KINDS, tags = scope, since = floor)), - RelayBasedFilter(relay = it, filter = ExplainedFilter(purpose = SubPurpose.PUBLIC_CHATS, kinds = RELAY_GROUP_PIN_KINDS, tags = scope, since = floor)), + RelayBasedFilter(relay = it, filter = ExplainedFilter(purpose = SubPurpose.RELAY_GROUPS, kinds = RELAY_GROUP_METADATA_KINDS, tags = scope, since = floor)), + RelayBasedFilter(relay = it, filter = ExplainedFilter(purpose = SubPurpose.RELAY_GROUPS, kinds = RELAY_GROUP_PIN_KINDS, tags = scope, since = floor)), ) } @@ -63,7 +63,7 @@ fun filterRelayGroupState( if (pinnedIds.isEmpty()) { emptyList() } else { - relays.map { RelayBasedFilter(relay = it, filter = ExplainedFilter(purpose = SubPurpose.PUBLIC_CHATS, ids = pinnedIds)) } + relays.map { RelayBasedFilter(relay = it, filter = ExplainedFilter(purpose = SubPurpose.RELAY_GROUPS, ids = pinnedIds)) } } return directory + pins diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupFilterAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupFilterAssembler.kt index aa5bfd453f..8e3d16982a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupFilterAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupFilterAssembler.kt @@ -25,6 +25,7 @@ import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManager import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.service.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.PerUniqueIdEoseManager import com.vitorpamplona.amethyst.service.relays.SincePerRelayMap import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.datasource.subassemblies.filterRelayGroupState @@ -35,13 +36,13 @@ import com.vitorpamplona.quartz.nip29RelayGroups.tags.GroupIdTag /** One on-screen group card's request to warm a single group. */ class RelayGroupCardWarmupQueryState( - val account: Account, + override val account: Account, val channel: RelayGroupChannel, /** When true, prefetch only recent content — the caller's screen already streams metadata. */ val contentOnly: Boolean = false, /** How many recent content events to prefetch ahead of a tap. */ val contentLimit: Int = RELAY_GROUP_WARMUP_LIMIT, -) +) : AccountScopedQuery /** * Default number of recent events to pull ahead of a tap — enough to fill the first screen AND drive @@ -96,7 +97,7 @@ class RelayGroupCardWarmupSubAssembler( relay = groupId.relayUrl, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, kinds = RELAY_GROUP_CARD_WARMUP_KINDS, tags = mapOf(GroupIdTag.TAG_NAME to listOf(groupId.id)), limit = key.contentLimit, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupFilterBuilders.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupFilterBuilders.kt index 4533686692..d432e55357 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupFilterBuilders.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupFilterBuilders.kt @@ -128,12 +128,12 @@ fun buildRelayGroupLiveStateFilter(groupId: GroupId): List = listOf( RelayBasedFilter( relay = groupId.relayUrl, - filter = ExplainedFilter(purpose = SubPurpose.PUBLIC_CHATS, kinds = RELAY_GROUP_METADATA_KINDS, tags = mapOf(GroupIdTag.TAG_NAME to listOf(groupId.id))), + filter = ExplainedFilter(purpose = SubPurpose.RELAY_GROUPS, entityIds = listOf(groupId.id), kinds = RELAY_GROUP_METADATA_KINDS, tags = mapOf(GroupIdTag.TAG_NAME to listOf(groupId.id))), ), // Pins stay in their own filter for the same reason the directory filters split them out. RelayBasedFilter( relay = groupId.relayUrl, - filter = ExplainedFilter(purpose = SubPurpose.PUBLIC_CHATS, kinds = RELAY_GROUP_PIN_KINDS, tags = mapOf(GroupIdTag.TAG_NAME to listOf(groupId.id))), + filter = ExplainedFilter(purpose = SubPurpose.RELAY_GROUPS, entityIds = listOf(groupId.id), kinds = RELAY_GROUP_PIN_KINDS, tags = mapOf(GroupIdTag.TAG_NAME to listOf(groupId.id))), ), ) @@ -287,8 +287,8 @@ fun buildRelayGroupStateFilters( val scope = mapOf(D_TAG to ids.distinct()) val since = sinceForRelay(relay) listOf( - RelayBasedFilter(relay = relay, filter = ExplainedFilter(purpose = SubPurpose.PUBLIC_CHATS, kinds = RELAY_GROUP_METADATA_KINDS, tags = scope, since = since)), - RelayBasedFilter(relay = relay, filter = ExplainedFilter(purpose = SubPurpose.PUBLIC_CHATS, kinds = RELAY_GROUP_PIN_KINDS, tags = scope, since = since)), + RelayBasedFilter(relay = relay, filter = ExplainedFilter(purpose = SubPurpose.RELAY_GROUPS, entityIds = ids.distinct(), kinds = RELAY_GROUP_METADATA_KINDS, tags = scope, since = since)), + RelayBasedFilter(relay = relay, filter = ExplainedFilter(purpose = SubPurpose.RELAY_GROUPS, entityIds = ids.distinct(), kinds = RELAY_GROUP_PIN_KINDS, tags = scope, since = since)), ) } @@ -326,7 +326,8 @@ fun buildRelayGroupJoinedChatTailFilter( relay = groupId.relayUrl, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, + entityIds = listOf(groupId.id), kinds = RELAY_GROUP_ALL_TIMELINE_KINDS, tags = mapOf(GroupIdTag.TAG_NAME to listOf(groupId.id)), since = sinceEpoch, @@ -362,7 +363,8 @@ fun buildRelayGroupPreviewFilter( relay = groupId.relayUrl, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, + entityIds = listOf(groupId.id), kinds = RELAY_GROUP_ALL_TIMELINE_KINDS, tags = mapOf(GroupIdTag.TAG_NAME to listOf(groupId.id)), since = sinceEpoch, @@ -383,7 +385,8 @@ fun buildRelayGroupAuxFilter( relay = groupId.relayUrl, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, + entityIds = listOf(groupId.id), kinds = RELAY_GROUP_AUX_KINDS, tags = mapOf(GroupIdTag.TAG_NAME to listOf(groupId.id)), since = sinceEpoch, @@ -400,7 +403,8 @@ fun buildRelayGroupOpenChatTailFilter( relay = groupId.relayUrl, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, + entityIds = listOf(groupId.id), kinds = RELAY_GROUP_OPEN_TAIL_KINDS, tags = mapOf(GroupIdTag.TAG_NAME to listOf(groupId.id)), since = sinceEpoch, @@ -424,7 +428,8 @@ fun buildRelayGroupHistoryFilters( relay = relay, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, + entityIds = listOf(groupId.id), kinds = RELAY_GROUP_ALL_TIMELINE_KINDS, tags = mapOf(GroupIdTag.TAG_NAME to listOf(groupId.id)), until = until, @@ -445,7 +450,7 @@ fun buildRelayGroupDirectoryFilter( relay = relay, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, kinds = RELAY_GROUP_DIRECTORY_KINDS, limit = RELAY_GROUP_DIRECTORY_LIMIT, since = sinceEpoch, @@ -469,7 +474,8 @@ fun buildRelayGroupThreadsHistoryFilters( relay = relay, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, + entityIds = listOf(groupId.id), kinds = RELAY_GROUP_THREAD_KINDS, tags = mapOf(GroupIdTag.TAG_NAME to listOf(groupId.id)), until = until, @@ -487,7 +493,8 @@ fun buildRelayGroupThreadsFilter( relay = groupId.relayUrl, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, + entityIds = listOf(groupId.id), kinds = RELAY_GROUP_THREAD_KINDS, tags = mapOf(GroupIdTag.TAG_NAME to listOf(groupId.id)), since = sinceEpoch, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsByAuthors.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsByAuthors.kt index 70fd3d0684..1e0e1291f8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsByAuthors.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsByAuthors.kt @@ -70,7 +70,7 @@ fun filterRelayGroupsByAuthors( relay = relay, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, authors = authorList, kinds = listOf(GroupMetadataEvent.KIND), limit = 200, @@ -82,7 +82,7 @@ fun filterRelayGroupsByAuthors( relay = relay, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, kinds = listOf(GroupAdminsEvent.KIND, GroupMembersEvent.KIND), tags = mapOf(PTag.TAG_NAME to authorList), limit = 200, @@ -102,7 +102,7 @@ fun filterRelayGroupsByAuthors( relay = relay, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, kinds = listOf(GroupMetadataEvent.KIND), tags = mapOf(DTag.TAG_NAME to rosterGroupIds), limit = 200, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsByGeohashes.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsByGeohashes.kt index a1d83e48fd..7b9c8b5922 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsByGeohashes.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsByGeohashes.kt @@ -41,7 +41,7 @@ fun filterRelayGroupsByGeohashes( relay = relay, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, kinds = listOf(GroupMetadataEvent.KIND), tags = mapOf(GeoHashTag.TAG_NAME to geotags.map { it.lowercase() }.sorted()), limit = 100, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsByHashtag.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsByHashtag.kt index 5c5b113e9a..98847f9bdd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsByHashtag.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsByHashtag.kt @@ -39,7 +39,7 @@ fun filterRelayGroupsByHashtag( relay = relay, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, kinds = listOf(GroupMetadataEvent.KIND), tags = mapOf(HashtagTag.TAG_NAME to hashtags.map { it.lowercase() }), limit = 200, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsDirectory.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsDirectory.kt index d6deb84bf5..06595c754b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsDirectory.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/subassemblies/FilterRelayGroupsDirectory.kt @@ -53,7 +53,7 @@ fun filterRelayGroupsDirectory( relay = relay, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.RELAY_GROUPS, kinds = RELAY_GROUP_DISCOVERY_KINDS, limit = 500, since = since, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FilterFollowingEphemeralChats.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FilterFollowingEphemeralChats.kt index a5897a49f3..6be3d19400 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FilterFollowingEphemeralChats.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FilterFollowingEphemeralChats.kt @@ -54,7 +54,7 @@ fun filterFollowingEphemeralChats( relay = it.key, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.EPHEMERAL_CHATS, kinds = listOf(EphemeralChatEvent.KIND), tags = mapOf("d" to it.value.sorted()), limit = 100, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FilterFollowingGeohashChats.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FilterFollowingGeohashChats.kt index 1ac81ad02c..29f3466e53 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FilterFollowingGeohashChats.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FilterFollowingGeohashChats.kt @@ -55,7 +55,10 @@ fun filterFollowingGeohashChats( relay = relay, filter = ExplainedFilter( - purpose = SubPurpose.PUBLIC_CHATS, + purpose = SubPurpose.GEOHASH_CHATS, + // One filter per relay carries every cell that relay serves, so all of them ride + // along and the screen fans them into a row each. + entityIds = cells.sorted(), kinds = listOf(GeohashChatEvent.KIND), tags = mapOf("g" to cells), limit = 100, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/SubPurposeLabels.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/SubPurposeLabels.kt index 0926c5268d..b4254ebbc5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/SubPurposeLabels.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/SubPurposeLabels.kt @@ -39,31 +39,38 @@ object SubPurposeLabels { fun labelOf(purpose: SubPurpose): Int = when (purpose) { // account — always on - SubPurpose.ACCOUNT_DATA -> R.string.kind_drafts - SubPurpose.PROFILE_METADATA -> R.string.kind_profile - SubPurpose.RELAY_LISTS -> R.string.kind_outbox_relays + SubPurpose.ACCOUNT_DATA -> R.string.relay_purpose_your_account + SubPurpose.PROFILE_METADATA -> R.string.relay_purpose_observing_profiles + SubPurpose.RELAY_LISTS -> R.string.relay_purpose_relay_list_finder SubPurpose.FOLLOW_LISTS -> R.string.kind_follow_list - SubPurpose.MODERATION -> R.string.kind_reports - SubPurpose.WALLET -> R.string.wallet + SubPurpose.MODERATION -> R.string.relay_purpose_reports_from_follows + SubPurpose.WALLET -> R.string.relay_purpose_your_wallet + SubPurpose.NUTZAP_INBOX -> R.string.relay_purpose_nutzap_inbox + SubPurpose.MINT_DIRECTORY -> R.string.relay_purpose_mint_directory + SubPurpose.NWC -> R.string.relay_purpose_nwc // messages — always on SubPurpose.NOTIFICATIONS -> R.string.route_notifications - SubPurpose.DIRECT_MESSAGES -> R.string.route_messages - SubPurpose.PUBLIC_CHATS -> R.string.relay_chat_title - SubPurpose.COMMUNITY_CHATS -> R.string.communities + SubPurpose.DIRECT_MESSAGES -> R.string.relay_purpose_dm_inbox + SubPurpose.PUBLIC_CHATS -> R.string.public_chat + SubPurpose.RELAY_GROUPS -> R.string.relay_purpose_relay_groups + SubPurpose.EPHEMERAL_CHATS -> R.string.relay_purpose_ephemeral_chats + SubPurpose.GEOHASH_CHATS -> R.string.relay_purpose_geohash_chats + SubPurpose.LIVE_CHAT -> R.string.relay_purpose_live_chat + SubPurpose.COMMUNITY_CHATS -> R.string.relay_purpose_community_chats SubPurpose.ENCRYPTED_GROUPS -> R.string.marmot_group SubPurpose.LIVE_ROOMS -> R.string.nests // feeds - SubPurpose.HOME_FEED -> R.string.route_home + SubPurpose.HOME_FEED -> R.string.relay_purpose_home_feed SubPurpose.DISCOVER_FEED -> R.string.route_discover SubPurpose.MEDIA_FEED -> R.string.relay_purpose_media SubPurpose.TAG_FEED -> R.string.relay_purpose_tags - SubPurpose.COMMUNITY_FEED -> R.string.communities + SubPurpose.COMMUNITY_FEED -> R.string.relay_purpose_community_feeds SubPurpose.TOPIC_FEED -> R.string.relay_purpose_topics // current screen SubPurpose.THREAD -> R.string.relay_purpose_thread SubPurpose.USER_PROFILE -> R.string.kind_profile SubPurpose.SEARCH -> R.string.relay_purpose_search - SubPurpose.ENGAGEMENT -> R.string.kind_reactions + SubPurpose.ENGAGEMENT -> R.string.relay_purpose_engagement SubPurpose.REFERENCED_EVENTS -> R.string.relay_purpose_referenced SubPurpose.ADD_ONS -> R.string.relay_purpose_add_ons SubPurpose.GAMES -> R.string.route_chess @@ -95,6 +102,10 @@ object SubPurposeLabels { SubPurpose.NOTIFICATIONS -> R.string.relay_explain_notifications SubPurpose.DIRECT_MESSAGES -> R.string.relay_explain_direct_messages SubPurpose.PUBLIC_CHATS -> R.string.relay_explain_public_chats + SubPurpose.RELAY_GROUPS -> R.string.relay_explain_relay_groups + SubPurpose.EPHEMERAL_CHATS -> R.string.relay_explain_ephemeral_chats + SubPurpose.GEOHASH_CHATS -> R.string.relay_explain_geohash_chats + SubPurpose.LIVE_CHAT -> R.string.relay_explain_live_chat SubPurpose.COMMUNITY_CHATS -> R.string.relay_explain_community_chats SubPurpose.ENCRYPTED_GROUPS -> R.string.relay_explain_encrypted_groups SubPurpose.LIVE_ROOMS -> R.string.relay_explain_live_rooms @@ -104,7 +115,12 @@ object SubPurposeLabels { SubPurpose.FOLLOW_LISTS -> R.string.relay_explain_follows SubPurpose.MODERATION -> R.string.relay_explain_moderation SubPurpose.WALLET -> R.string.relay_explain_wallet + SubPurpose.NUTZAP_INBOX -> R.string.relay_explain_nutzap_inbox + SubPurpose.MINT_DIRECTORY -> R.string.relay_explain_mint_directory + SubPurpose.NWC -> R.string.relay_explain_nwc SubPurpose.HOME_FEED -> R.string.relay_explain_home + SubPurpose.ENGAGEMENT -> R.string.relay_explain_engagement + SubPurpose.REFERENCED_EVENTS -> R.string.relay_explain_referenced else -> null } } diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index d55d790cea..6dcd4e12e3 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -2081,10 +2081,39 @@ Topics Conversation Search - Quoted posts + Finding Missing Events + Observing Events + Fetches events by id that something on your screen refers to but you don\'t have yet — a quote, a reply\'s parent, a thread root. + Watches the events currently rendered for new replies, reactions, reposts, zaps and reports, so counts update while you read. Add-ons Relay info Other + + Relay List Finder + Observing Profiles + Your Account\'s data + Home Feed + Relay Groups + + %1$d group + %1$d groups + + Ephemeral Chats + Location Chats + Live Stream Chat + NIP-29 groups you joined. Each group lives on one host relay, so the app connects to every relay that hosts a group of yours. + Chat rooms that keep no history — messages exist only while you are connected, so these stay subscribed to receive anything at all. + Location-based rooms for the areas you follow, asked of the relays that carry them. + Chat and zap goals attached to live streams you have open or follow. + DM Inbox + Wallet + Nutzap Inbox + Mint Directory + Wallet Connect + Community Chats + Community Feeds @@ -2098,9 +2127,13 @@ Profiles of the people currently on screen. Finds which relays each person publishes to, so their posts can be fetched from the right place. Follow lists, used to build your feed and your web of trust. - Reports written by people you follow, asked of each relay those people post to. - Your mints, wallet state and incoming nutzaps. - Active Subscriptions + Reports your follows wrote about the profiles currently on your screen, asked of each relay those follows post to. + Reports from Follows + Your own wallet events, read back from the relays you published them to. + Listens on your nutzap relays plus your inbox and DM relays, so a payment cannot slip past. + Looks across relays for which mints exist and which ones people recommend. + Notifications from your connected wallet. + Active Relay Subscriptions @@ -2118,6 +2151,8 @@ %1$s \u00b7 %2$s Not attributed to an account All + %1$d%% of all + subscriptions filters relays requests reqs connections why diagnostics Posts by people you follow, read from the relays each of them publishes to. Connecting to inbox relays\u2026 Always-on notification service diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/subscriptions/SubPurpose.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/subscriptions/SubPurpose.kt index cc865fdbbd..926e11d11f 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/subscriptions/SubPurpose.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/subscriptions/SubPurpose.kt @@ -69,9 +69,28 @@ enum class SubPurpose( /** Reports (kind 1984), mute lists, spam and ban state. */ MODERATION(SubPurposeGroup.ACCOUNT, runsInBackground = true), - /** Cashu wallet, nutzaps, mints and NWC. */ + /** + * Your own NIP-60 wallet state, read back from your outbox relays. Narrow by construction. + * + * Split from the wider wallet jobs because they answer different questions: this is "restore my + * wallet", [NUTZAP_INBOX] is "listen everywhere someone might pay me", and [MINT_DIRECTORY] is + * "what mints exist". Lumping them made a handful of relays look like a dozen. + */ WALLET(SubPurposeGroup.ACCOUNT, runsInBackground = true), + /** + * Inbound nutzaps (kind 9321). Deliberately the **union** of the NIP-61 `10019` relays, the + * NIP-65 inbox and the DM relays — per the assembler, "so a nutzap can't slip past us". That + * union is why this is wide, and it is a choice rather than an accident. + */ + NUTZAP_INBOX(SubPurposeGroup.ACCOUNT, runsInBackground = true), + + /** Mint announcements and recommendations — a discovery query, so it fans out. */ + MINT_DIRECTORY(SubPurposeGroup.ACCOUNT), + + /** Nostr Wallet Connect notifications, on the wallet-connect relay. */ + NWC(SubPurposeGroup.ACCOUNT, runsInBackground = true), + // ---- things addressed to me: always on --------------------------------- /** Mentions, reactions, reposts and zaps addressed to me (`#p` = me). Inbox relays. */ @@ -80,9 +99,28 @@ enum class SubPurpose( /** NIP-17 gift wraps and NIP-04 legacy DMs. DM relays. */ DIRECT_MESSAGES(SubPurposeGroup.MESSAGES, runsInBackground = true), - /** NIP-28/29 public channels and relay groups. */ + /** + * NIP-28 public channels only. + * + * This was a catch-all that also carried NIP-29 relay groups, ephemeral chats, geohash chats and + * live-stream chat — five protocols in one row labelled with the NIP-29 name, so the subscription + * screen could not say where any of them came from. They are separate below, each named and + * counted on its own. + */ PUBLIC_CHATS(SubPurposeGroup.MESSAGES, runsInBackground = true), + /** NIP-29 relay groups. Each group is keyed by (id, host relay). */ + RELAY_GROUPS(SubPurposeGroup.MESSAGES, runsInBackground = true), + + /** NIP-C7 ephemeral chats — no history is stored, so only live delivery exists. */ + EPHEMERAL_CHATS(SubPurposeGroup.MESSAGES, runsInBackground = true), + + /** Location-scoped chat rooms. */ + GEOHASH_CHATS(SubPurposeGroup.MESSAGES, runsInBackground = true), + + /** Chat and zap goals attached to live streams. */ + LIVE_CHAT(SubPurposeGroup.MESSAGES, runsInBackground = true), + /** Concord and Buzz community planes. */ COMMUNITY_CHATS(SubPurposeGroup.MESSAGES, runsInBackground = true),