diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/SoftwareAppsSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/SoftwareAppsSubAssembler.kt index b1eeed1aad..88710a4665 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/SoftwareAppsSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/SoftwareAppsSubAssembler.kt @@ -44,7 +44,12 @@ class SoftwareAppsSubAssembler( ): List { val feedSettings = key.followsPerRelay() - return makeSoftwareAppsFilter(feedSettings, since, key.feedStates.softwareAppsFeed.lastNoteCreatedAtIfFilled()) + return makeSoftwareAppsFilter( + feedSettings, + since, + key.feedStates.softwareAppsFeed.lastNoteCreatedAtIfFilled(), + key.account.blockedRelayList.flow.value, + ) } override fun user(key: SoftwareAppsQueryState) = key.account.userProfile() @@ -77,6 +82,13 @@ class SoftwareAppsSubAssembler( invalidateFilters() } }, + key.scope.launch(Dispatchers.IO) { + // Re-evaluate when the user blocks/unblocks zapstore's relay so the + // global Apps feed stops/starts querying it without a restart. + key.account.blockedRelayList.flow.collectLatest { + invalidateFilters() + } + }, key.account.scope.launch(Dispatchers.IO) { key.feedStates.softwareAppsFeed.lastNoteCreatedAtWhenFullyLoaded.sample(5000).collectLatest { invalidateFilters() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/SubAssemblyHelper.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/SubAssemblyHelper.kt index be86fd0cdc..6dbfbf2fc2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/SubAssemblyHelper.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/SubAssemblyHelper.kt @@ -33,16 +33,18 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.softwareapps.datasource.sub import com.vitorpamplona.amethyst.ui.screen.loggedIn.softwareapps.datasource.subassemblies.filterSoftwareAppsByMutedAuthors import com.vitorpamplona.amethyst.ui.screen.loggedIn.softwareapps.datasource.subassemblies.filterSoftwareAppsGlobal import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl fun makeSoftwareAppsFilter( feedSettings: IFeedTopNavPerRelayFilterSet, since: SincePerRelayMap?, defaultSince: Long? = null, + blockedRelays: Set = emptySet(), ): List = when (feedSettings) { is AllFollowsTopNavPerRelayFilterSet -> filterSoftwareAppsByFollows(feedSettings, since, defaultSince) is AuthorsTopNavPerRelayFilterSet -> filterSoftwareAppsByAuthors(feedSettings, since, defaultSince) - is GlobalTopNavPerRelayFilterSet -> filterSoftwareAppsGlobal(feedSettings, since, defaultSince) + is GlobalTopNavPerRelayFilterSet -> filterSoftwareAppsGlobal(feedSettings, since, defaultSince, blockedRelays) is HashtagTopNavPerRelayFilterSet -> filterSoftwareAppsByHashtag(feedSettings, since, defaultSince) is MutedAuthorsTopNavPerRelayFilterSet -> filterSoftwareAppsByMutedAuthors(feedSettings, since, defaultSince) else -> emptyList() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/subassemblies/FilterSoftwareAppsGlobal.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/subassemblies/FilterSoftwareAppsGlobal.kt index a37c99ba02..056c3a067f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/subassemblies/FilterSoftwareAppsGlobal.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/subassemblies/FilterSoftwareAppsGlobal.kt @@ -26,22 +26,40 @@ import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.application.Softw import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.release.SoftwareReleaseEvent import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.normalizeRelayUrl + +// zapstore's relay indexes the entire software-app catalog (NIP-82), so the +// global Apps feed always queries it in addition to the user's own relays — +// unless the user has explicitly added it to their blocked relay list. +val ZAPSTORE_APP_RELAY: NormalizedRelayUrl = "wss://relay.zapstore.dev".normalizeRelayUrl() fun filterSoftwareAppsGlobal( relays: GlobalTopNavPerRelayFilterSet, since: SincePerRelayMap?, defaultSince: Long? = null, + blockedRelays: Set = emptySet(), ): List { - if (relays.set.isEmpty()) return emptyList() + val relayUrls = + if (ZAPSTORE_APP_RELAY in blockedRelays) { + relays.set.keys + } else { + relays.set.keys + ZAPSTORE_APP_RELAY + } - return relays.set.map { - val sinceForRelay = since?.get(it.key)?.time ?: defaultSince + if (relayUrls.isEmpty()) return emptyList() + + return relayUrls.map { relay -> + val sinceForRelay = since?.get(relay)?.time ?: defaultSince RelayBasedFilter( - relay = it.key, + relay = relay, filter = Filter( kinds = listOf(SoftwareApplicationEvent.KIND, SoftwareReleaseEvent.KIND), - limit = 200, + // Keep the limit < 100. Relays such as zapstore's score filter + // specificity and treat a limit >= 100 (or none) as too vague, + // rejecting the whole REQ with "filters are too vague". + limit = 99, since = sinceForRelay, ), )