diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt index 899c81b4b0..72706304ec 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt @@ -20,9 +20,11 @@ */ package com.vitorpamplona.amethyst.service.relayClient.reqCommand +import com.vitorpamplona.amethyst.commons.relayClient.apps.recommendations.ProfileAppRecommendationsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.articles.ArticlesFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.assemblers.CashuMintDirectoryFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.badges.BadgesFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.badges.profile.ProfileBadgesFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.calendars.CalendarsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.channel.ChannelFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.chess.ChessFilterAssembler @@ -36,10 +38,12 @@ import com.vitorpamplona.amethyst.commons.relayClient.geohash.GeoHashFilterAssem import com.vitorpamplona.amethyst.commons.relayClient.gitRepo.RepositoryFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.gitRepositories.GitRepositoriesFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.highlights.HighlightsFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.home.HomeFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.livestreams.LiveStreamsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.longs.LongsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.music.MusicPlaylistsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.music.MusicTracksFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.napplets.ConnectedAppsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.napplets.NappletsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.nests.NestsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.nip47WalletConnect.NWCPaymentFilterAssembler @@ -58,6 +62,7 @@ import com.vitorpamplona.amethyst.commons.relayClient.relay.RelayFeedFilterAssem import com.vitorpamplona.amethyst.commons.relayClient.relays.RelayInfoNip66FilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.shorts.ShortsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.softwareapps.SoftwareAppsFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.thread.ThreadFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.url.UrlFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.video.VideoFilterAssembler @@ -68,8 +73,6 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.Account import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountForegroundFilterAssembler import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.ChannelFinderFilterAssemblyGroup import com.vitorpamplona.amethyst.service.relayClient.searchCommand.SearchFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.apps.recommendations.datasource.ProfileAppRecommendationsFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.profile.datasource.ProfileBadgesFilterAssembler import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.datasource.ChatroomFilterAssembler import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelFilterAssembler import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelHistoryFilterAssembler @@ -86,11 +89,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayG import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource.ChatroomListFilterAssembler import com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.datasource.FollowPackFeedFilterAssembler import com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.datasource.HashtagFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.HomeFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.napplets.datasource.ConnectedAppsFilterAssembler import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.datasource.NestRoomFilterAssembler import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.datasource.NestRoomLivenessAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources.ThreadFilterAssembler import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.RelayOfflineTracker import com.vitorpamplona.quartz.nip01Core.relay.client.auth.IAuthStatus @@ -156,7 +156,7 @@ class RelaySubscriptionsCoordinator( val chatroom = ChatroomFilterAssembler(client) val community = CommunityFilterAssembler(cache, client) val gitRepository = RepositoryFilterAssembler(cache, client) - val thread = ThreadFilterAssembler(client) + val thread = ThreadFilterAssembler(cache, client) val profile = UserProfileFilterAssembler(cache, client) val hashtags = HashtagFilterAssembler(client) val geohashes = GeoHashFilterAssembler(client) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssemblerSubscription.kt index 28e7c463b5..5a4c15633f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssemblerSubscription.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.apps.recommendations.datas import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.relayClient.apps.recommendations.ProfileAppRecommendationsQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -29,7 +30,12 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel fun ProfileAppRecommendationsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { val state = remember(accountViewModel.account) { - ProfileAppRecommendationsQueryState(accountViewModel.account) + val account = accountViewModel.account + ProfileAppRecommendationsQueryState( + account = account, + outboxRelays = account.outboxRelays.flow, + defaultGlobalRelays = account.defaultGlobalRelays.flow, + ) } LifecycleAwareKeyDataSourceSubscription(state, accountViewModel.dataSources().profileAppRecommendations) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesFilterAssemblerSubscription.kt index cfb44d7e4e..459462b1cd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesFilterAssemblerSubscription.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.profile.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.relayClient.badges.profile.ProfileBadgesQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -29,7 +30,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel fun ProfileBadgesFilterAssemblerSubscription(accountViewModel: AccountViewModel) { val state = remember(accountViewModel.account) { - ProfileBadgesQueryState(accountViewModel.account) + val account = accountViewModel.account + ProfileBadgesQueryState(account, account.notificationRelays.flow) } LifecycleAwareKeyDataSourceSubscription(state, accountViewModel.dataSources().profileBadges) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterSubAssembler.kt index d8bb1623a3..d392e9ceb3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterSubAssembler.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.datasourc import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUserFollowsByOutboxTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUserFollowsByProxyTopNavFilter import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.SingleSubEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.home.nip65Follows.filterHomePostsByAuthors import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip65Follows.filterHomePostsByAuthors import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/HomeFilterAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/HomeFilterAssembler.kt deleted file mode 100644 index cf73606cc4..0000000000 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/HomeFilterAssembler.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2025 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.amethyst.ui.screen.loggedIn.home.datasource - -import androidx.compose.runtime.Stable -import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery -import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountFeedContentStates -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip65Follows.HomeOutboxEventsEoseManager -import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient -import kotlinx.coroutines.CoroutineScope - -// This allows multiple screen to be listening to tags, even the same tag - -@Stable -class HomeQueryState( - override val account: Account, - val feedState: AccountFeedContentStates, - val scope: CoroutineScope, -) : AccountScopedQuery - -@Stable -class HomeFilterAssembler( - client: INostrClient, -) : ComposeSubscriptionManager() { - val group = - listOf( - HomeOutboxEventsEoseManager(client, ::allKeys), - // HomeOutboxUsersEoseManager(client, ::allKeys), - // We can break it down, one for each sub if needed. - // HashtagEventsFilterSubAssembler(client, ::allKeys), - // GeohashEventsFilterSubAssembler(client, ::allKeys), - // CommunityEventsFilterSubAssembler(client, ::allKeys), - // MixGeohashHashtagsCommunityEoseManager(client, ::allKeys), - ) - - override fun invalidateKeys() = invalidateFilters() - - override fun invalidateFilters() = group.forEach { it.invalidateFilters() } - - override fun destroy() = group.forEach { it.destroy() } -} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/HomeFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/HomeFilterAssemblerSubscription.kt index bdec0fcb9e..6911d05e39 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/HomeFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/HomeFilterAssemblerSubscription.kt @@ -23,6 +23,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.relayClient.home.HomeFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.home.HomeQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -43,10 +45,15 @@ fun HomeFilterAssemblerSubscription( // even if they are tracking the same tag. val state = remember(accountViewModel.account) { + val account = accountViewModel.account HomeQueryState( - accountViewModel.account, - accountViewModel.feedStates, - accountViewModel.viewModelScope, + account = account, + listName = account.settings.defaultHomeFollowList, + followsPerRelay = account.liveHomeFollowListsPerRelay, + scope = accountViewModel.viewModelScope, + newThreads = accountViewModel.feedStates.homeNewThreads, + replies = accountViewModel.feedStates.homeReplies, + enabledHomeFeedTypes = account.settings.enabledHomeFeedTypes, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsFilterAssemblerSubscription.kt index b970fad2f7..63d6000dce 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsFilterAssemblerSubscription.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.napplets.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.relayClient.napplets.ConnectedAppsQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey @@ -33,7 +34,8 @@ fun ConnectedAppsFilterAssemblerSubscription( ) { val state = remember(accountViewModel.account, authors) { - ConnectedAppsQueryState(accountViewModel.account, authors) + val account = accountViewModel.account + ConnectedAppsQueryState(account, authors, account.homeRelays.flow) } LifecycleAwareKeyDataSourceSubscription(state, accountViewModel.dataSources().connectedApps) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/ThreadFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/ThreadFilterAssemblerSubscription.kt index eb9c534ac7..ad12f21afc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/ThreadFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/ThreadFilterAssemblerSubscription.kt @@ -24,6 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription +import com.vitorpamplona.amethyst.commons.relayClient.thread.ThreadFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.thread.ThreadQueryState import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey @@ -48,7 +50,7 @@ fun ThreadFilterAssemblerSubscription( // even if they are tracking the same tag. val state = remember(eventId) { - ThreadQueryState(eventId, account) + ThreadQueryState(eventId, account, account.followPlusAllMineWithSearch.flow) } LifecycleAwareKeyDataSourceSubscription(state, filterAssembler) diff --git a/commons/plans/2026-08-30-commons-migration-sweep.md b/commons/plans/2026-08-30-commons-migration-sweep.md index 65c8a3835e..efbf6a8f94 100644 --- a/commons/plans/2026-08-30-commons-migration-sweep.md +++ b/commons/plans/2026-08-30-commons-migration-sweep.md @@ -693,6 +693,33 @@ change each); `followPacks/feed` (dispatches to the app-side home filters); `launchChatFeedToggleObserver`); `nests/NestRoom*`, `relayGroup/*`, `concord/*` and `home/` (`Account` + `LocalCache` live streams + `AccountViewModel`). +### Single-relay-read families and the home feed landed (2026-09-05, after #4059) + +The four families that read one relay-set state off `Account` now carry that +set as a `StateFlow` on their key, the way `SearchQueryState` does: +`ProfileAppRecommendationsQueryState(outboxRelays, defaultGlobalRelays)`, +`ProfileBadgesQueryState(notificationRelays)`, +`ConnectedAppsQueryState(homeRelays)` and `ThreadQueryState(defaultRelays)`. +Thread also takes the cache (`ThreadFilterAssembler(cache, client)`; its two +sub-assemblers run `ThreadAssembler(cache)`). All live under +`commons/relayClient/{apps/recommendations,badges/profile,napplets,thread}`. + +The home feed moved whole: the `FilterHomePosts*` dispatchers under +`commons/relayClient/home//`, and `HomeOutboxEventsEoseManager` is now a +`TopNavFeedSubAssembler` whose key carries the new-threads and +replies floors plus `enabledHomeFeedTypes`; the Settings › Home toggle is an +`extraInvalidators` entry (still `drop(1)`), and the disabled-kinds stripping +is unchanged. Deltas as for the other feeds: watchers on the screen scope, +follows sampler 500 ms (was 1000). The commented-out alternative +sub-assemblers in `HomeFilterAssembler` were dropped. + +What remains in `ui/screen/**/datasource*/` (92 files) is the Compose glue — +one `*Subscription.kt` per feature, which builds the key from +`AccountViewModel` — plus the families that need Wave 4: `hashtag/` +(`Account.followsPerRelay`), `followPacks/feed` (`Account.proxyRelayList`, +`blockedRelayList`, `cache`), `chats/*`, `nests/NestRoom*`, `relayGroup/*`, +`concord/*`, and `wallet`'s and `polls/results`' composables. + ### Desktop `subscriptions/FilterBuilders.kt` — investigated, not migrated (2026-09-05) The audit listed this 742-line file as a hand-rolled copy of ~34 diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/FilterAppRecommendations.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/apps/recommendations/FilterAppRecommendations.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/FilterAppRecommendations.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/apps/recommendations/FilterAppRecommendations.kt index 62b8d3fec7..73656df635 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/FilterAppRecommendations.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/apps/recommendations/FilterAppRecommendations.kt @@ -18,7 +18,7 @@ * 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.amethyst.ui.screen.loggedIn.apps.recommendations.datasource +package com.vitorpamplona.amethyst.commons.relayClient.apps.recommendations import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/apps/recommendations/ProfileAppRecommendationsFilterAssembler.kt similarity index 74% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/apps/recommendations/ProfileAppRecommendationsFilterAssembler.kt index cc5c367a5d..b359a8ce3f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/apps/recommendations/ProfileAppRecommendationsFilterAssembler.kt @@ -18,16 +18,25 @@ * 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.amethyst.ui.screen.loggedIn.apps.recommendations.datasource +package com.vitorpamplona.amethyst.commons.relayClient.apps.recommendations import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.model.IAccount import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import kotlinx.coroutines.flow.StateFlow +/** + * @param outboxRelays the user's own outbox relays, where their kind-31989 recommendations live. + * @param defaultGlobalRelays follows' outboxes plus the user's relays, where recent kind-31990 + * app definitions are discovered. + */ class ProfileAppRecommendationsQueryState( - override val account: Account, + override val account: IAccount, + val outboxRelays: StateFlow>, + val defaultGlobalRelays: StateFlow>, ) : AccountScopedQuery @Stable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsSubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/apps/recommendations/ProfileAppRecommendationsSubAssembler.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsSubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/apps/recommendations/ProfileAppRecommendationsSubAssembler.kt index 32b3196307..491709398a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsSubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/apps/recommendations/ProfileAppRecommendationsSubAssembler.kt @@ -18,7 +18,7 @@ * 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.amethyst.ui.screen.loggedIn.apps.recommendations.datasource +package com.vitorpamplona.amethyst.commons.relayClient.apps.recommendations import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap @@ -37,9 +37,9 @@ class ProfileAppRecommendationsSubAssembler( ): List = filterMyAppRecommendations( pubkey = user(key).pubkeyHex, - relays = key.account.outboxRelays.flow.value, + relays = key.outboxRelays.value, ) + filterRecentAppDefinitions( - relays = key.account.defaultGlobalRelays.flow.value, + relays = key.defaultGlobalRelays.value, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/FilterReceivedBadgeAwards.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/badges/profile/FilterReceivedBadgeAwards.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/FilterReceivedBadgeAwards.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/badges/profile/FilterReceivedBadgeAwards.kt index 754aab2c50..7c716f196f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/FilterReceivedBadgeAwards.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/badges/profile/FilterReceivedBadgeAwards.kt @@ -18,7 +18,7 @@ * 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.amethyst.ui.screen.loggedIn.badges.profile.datasource +package com.vitorpamplona.amethyst.commons.relayClient.badges.profile import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/badges/profile/ProfileBadgesFilterAssembler.kt similarity index 80% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/badges/profile/ProfileBadgesFilterAssembler.kt index f9bd26590b..d68f987337 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/badges/profile/ProfileBadgesFilterAssembler.kt @@ -18,16 +18,20 @@ * 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.amethyst.ui.screen.loggedIn.badges.profile.datasource +package com.vitorpamplona.amethyst.commons.relayClient.badges.profile import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.model.IAccount import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import kotlinx.coroutines.flow.StateFlow +/** @param notificationRelays the user's inbox relays, where badge awards addressed to them land. */ class ProfileBadgesQueryState( - override val account: Account, + override val account: IAccount, + val notificationRelays: StateFlow>, ) : AccountScopedQuery @Stable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesSubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/badges/profile/ProfileBadgesSubAssembler.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesSubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/badges/profile/ProfileBadgesSubAssembler.kt index 0ed0d13e63..ed00438955 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesSubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/badges/profile/ProfileBadgesSubAssembler.kt @@ -18,7 +18,7 @@ * 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.amethyst.ui.screen.loggedIn.badges.profile.datasource +package com.vitorpamplona.amethyst.commons.relayClient.badges.profile import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap @@ -37,6 +37,6 @@ class ProfileBadgesSubAssembler( ): List = filterReceivedBadgeAwards( pubkey = user(key).pubkeyHex, - relays = key.account.notificationRelays.flow.value, + relays = key.notificationRelays.value, ) } diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/HomeFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/HomeFilterAssembler.kt new file mode 100644 index 0000000000..388be70d53 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/HomeFilterAssembler.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 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.amethyst.commons.relayClient.home + +import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.model.HomeFeedType +import com.vitorpamplona.amethyst.commons.model.IAccount +import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedTopNavPerRelayFilterSet +import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter +import com.vitorpamplona.amethyst.commons.relayClient.home.nip65Follows.HomeOutboxEventsEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.topNavFeeds.TopNavFeedFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.topNavFeeds.TopNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState +import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.StateFlow + +/** + * Key for the home feed: the top-nav selection, the new-threads and replies floors that bound + * `since`, and the Settings › Home content-type toggles whose disabled groups are stripped from + * every home REQ. + */ +@Stable +class HomeQueryState( + account: IAccount, + listName: StateFlow, + followsPerRelay: StateFlow, + scope: CoroutineScope, + val newThreads: FeedContentState, + val replies: FeedContentState, + val enabledHomeFeedTypes: StateFlow>, +) : TopNavFeedQueryState(account, listName, followsPerRelay, scope, listOf(newThreads, replies)) + +class HomeFilterAssembler( + client: INostrClient, +) : TopNavFeedFilterAssembler({ keys -> listOf(HomeOutboxEventsEoseManager(client, keys)) }) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip01Core/FilterHomePostsByGeohashes.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip01Core/FilterHomePostsByGeohashes.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip01Core/FilterHomePostsByGeohashes.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip01Core/FilterHomePostsByGeohashes.kt index ca164d6978..f366992b85 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip01Core/FilterHomePostsByGeohashes.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip01Core/FilterHomePostsByGeohashes.kt @@ -18,7 +18,7 @@ * 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.amethyst.ui.screen.loggedIn.home.datasource.nip01Core +package com.vitorpamplona.amethyst.commons.relayClient.home.nip01Core import com.vitorpamplona.amethyst.commons.model.topNavFeeds.aroundMe.LocationTopNavPerRelayFilterSet import com.vitorpamplona.amethyst.commons.relayClient.nip22Comments.filterHomePostsByScopes diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip01Core/FilterHomePostsByGlobal.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip01Core/FilterHomePostsByGlobal.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip01Core/FilterHomePostsByGlobal.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip01Core/FilterHomePostsByGlobal.kt index 0d45adefc5..fc85579ddb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip01Core/FilterHomePostsByGlobal.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip01Core/FilterHomePostsByGlobal.kt @@ -18,15 +18,15 @@ * 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.amethyst.ui.screen.loggedIn.home.datasource.nip01Core +package com.vitorpamplona.amethyst.commons.relayClient.home.nip01Core import com.vitorpamplona.amethyst.commons.model.topNavFeeds.global.GlobalTopNavPerRelayFilterSet +import com.vitorpamplona.amethyst.commons.relayClient.home.nip65Follows.HomePostsConversationKinds +import com.vitorpamplona.amethyst.commons.relayClient.home.nip65Follows.HomePostsNewThreadKinds1 +import com.vitorpamplona.amethyst.commons.relayClient.home.nip65Follows.HomePostsNewThreadKinds2 import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip65Follows.HomePostsConversationKinds -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip65Follows.HomePostsNewThreadKinds1 -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip65Follows.HomePostsNewThreadKinds2 import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter fun filterHomePostsByGlobal( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip01Core/FilterHomePostsByHashtags.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip01Core/FilterHomePostsByHashtags.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip01Core/FilterHomePostsByHashtags.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip01Core/FilterHomePostsByHashtags.kt index 7ec5adf509..a6a97fa7f7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip01Core/FilterHomePostsByHashtags.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip01Core/FilterHomePostsByHashtags.kt @@ -18,7 +18,7 @@ * 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.amethyst.ui.screen.loggedIn.home.datasource.nip01Core +package com.vitorpamplona.amethyst.commons.relayClient.home.nip01Core import com.vitorpamplona.amethyst.commons.model.topNavFeeds.hashtag.HashtagTopNavPerRelayFilterSet import com.vitorpamplona.amethyst.commons.relayClient.nip22Comments.filterHomePostsByScopes diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip01Core/FilterHomePostsByRelay.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip01Core/FilterHomePostsByRelay.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip01Core/FilterHomePostsByRelay.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip01Core/FilterHomePostsByRelay.kt index 40390e502d..7f4bf50fb3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip01Core/FilterHomePostsByRelay.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip01Core/FilterHomePostsByRelay.kt @@ -18,15 +18,15 @@ * 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.amethyst.ui.screen.loggedIn.home.datasource.nip01Core +package com.vitorpamplona.amethyst.commons.relayClient.home.nip01Core import com.vitorpamplona.amethyst.commons.model.topNavFeeds.relay.RelayTopNavPerRelayFilterSet +import com.vitorpamplona.amethyst.commons.relayClient.home.nip65Follows.HomePostsConversationKinds +import com.vitorpamplona.amethyst.commons.relayClient.home.nip65Follows.HomePostsNewThreadKinds1 +import com.vitorpamplona.amethyst.commons.relayClient.home.nip65Follows.HomePostsNewThreadKinds2 import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip65Follows.HomePostsConversationKinds -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip65Follows.HomePostsNewThreadKinds1 -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip65Follows.HomePostsNewThreadKinds2 import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter fun filterHomePostsByRelay( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip65Follows/FilterHomePostsByAllFollows.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip65Follows/FilterHomePostsByAllFollows.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip65Follows/FilterHomePostsByAllFollows.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip65Follows/FilterHomePostsByAllFollows.kt index dcb77e04b8..28bb67f9dd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip65Follows/FilterHomePostsByAllFollows.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip65Follows/FilterHomePostsByAllFollows.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.amethyst.ui.screen.loggedIn.home.datasource.nip65Follows +package com.vitorpamplona.amethyst.commons.relayClient.home.nip65Follows import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allFollows.AllFollowsTopNavPerRelayFilterSet +import com.vitorpamplona.amethyst.commons.relayClient.home.nip01Core.filterHomePostsByGeohashes +import com.vitorpamplona.amethyst.commons.relayClient.home.nip01Core.filterHomePostsByHashtags +import com.vitorpamplona.amethyst.commons.relayClient.home.nip72Communities.filterHomePostsFromAllCommunities import com.vitorpamplona.amethyst.commons.relayClient.nip22Comments.filterHomePostsByScopes import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip01Core.filterHomePostsByGeohashes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip01Core.filterHomePostsByHashtags -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip72Communities.filterHomePostsFromAllCommunities import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter fun filterHomePostsByAllFollows( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip65Follows/FilterHomePostsByAuthors.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip65Follows/FilterHomePostsByAuthors.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip65Follows/FilterHomePostsByAuthors.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip65Follows/FilterHomePostsByAuthors.kt index c5b033a10c..eb2037cd10 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip65Follows/FilterHomePostsByAuthors.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip65Follows/FilterHomePostsByAuthors.kt @@ -18,7 +18,7 @@ * 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.amethyst.ui.screen.loggedIn.home.datasource.nip65Follows +package com.vitorpamplona.amethyst.commons.relayClient.home.nip65Follows import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.author.AuthorsTopNavPerRelayFilterSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsTopNavPerRelayFilterSet diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip65Follows/HomeOutboxEventsEoseManager.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip65Follows/HomeOutboxEventsEoseManager.kt similarity index 53% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip65Follows/HomeOutboxEventsEoseManager.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip65Follows/HomeOutboxEventsEoseManager.kt index 0b9d877aac..ec3e118400 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip65Follows/HomeOutboxEventsEoseManager.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip65Follows/HomeOutboxEventsEoseManager.kt @@ -18,11 +18,9 @@ * 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.amethyst.ui.screen.loggedIn.home.datasource.nip65Follows +package com.vitorpamplona.amethyst.commons.relayClient.home.nip65Follows import com.vitorpamplona.amethyst.commons.model.HomeFeedType -import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allFollows.AllFollowsTopNavPerRelayFilterSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.aroundMe.LocationTopNavPerRelayFilterSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.favoriteAlgoFeeds.FavoriteAlgoFeedTopNavPerRelayFilterSet @@ -33,39 +31,38 @@ import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.author.Aut import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.community.SingleCommunityTopNavPerRelayFilterSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsTopNavPerRelayFilterSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.relay.RelayTopNavPerRelayFilterSet -import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserAndFollowListEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.home.HomeQueryState +import com.vitorpamplona.amethyst.commons.relayClient.home.nip01Core.filterHomePostsByGeohashes +import com.vitorpamplona.amethyst.commons.relayClient.home.nip01Core.filterHomePostsByGlobal +import com.vitorpamplona.amethyst.commons.relayClient.home.nip01Core.filterHomePostsByHashtags +import com.vitorpamplona.amethyst.commons.relayClient.home.nip01Core.filterHomePostsByRelay +import com.vitorpamplona.amethyst.commons.relayClient.home.nip72Communities.filterHomePostsByAllCommunities +import com.vitorpamplona.amethyst.commons.relayClient.home.nip72Communities.filterHomePostsByCommunity +import com.vitorpamplona.amethyst.commons.relayClient.home.nip90AlgoFeeds.filterHomePostsByAlgoFeedIds import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.scopedTo +import com.vitorpamplona.amethyst.commons.relayClient.topNavFeeds.TopNavFeedSubAssembler import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.HomeQueryState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip01Core.filterHomePostsByGeohashes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip01Core.filterHomePostsByGlobal -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip01Core.filterHomePostsByHashtags -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip01Core.filterHomePostsByRelay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip72Communities.filterHomePostsByAllCommunities -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip72Communities.filterHomePostsByCommunity -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip90AlgoFeeds.filterHomePostsByAlgoFeedIds import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter -import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.drop -import kotlinx.coroutines.flow.sample -import kotlinx.coroutines.launch +/** + * The home feed's REQ builder: dispatches the top-nav selection to the home filters, bounded by the + * new-threads and replies floors, and drops the kinds the user turned off in Settings › Home. + */ class HomeOutboxEventsEoseManager( client: INostrClient, allKeys: () -> Set, -) : PerUserAndFollowListEoseManager(client, allKeys) { +) : TopNavFeedSubAssembler(client, allKeys) { override fun updateFilter( key: HomeQueryState, since: SincePerRelayMap?, - ): List? { - val feedSettings = key.followsPerRelay() - val newThreadSince = key.feedState.homeNewThreads.lastNoteCreatedAtIfFilled() - val repliesSince = key.feedState.homeReplies.lastNoteCreatedAtIfFilled() + ): List { + val feedSettings = key.followsPerRelay.value + val newThreadSince = key.newThreads.lastNoteCreatedAtIfFilled() + val repliesSince = key.replies.lastNoteCreatedAtIfFilled() + val base = when (feedSettings) { is AllCommunitiesTopNavPerRelayFilterSet -> filterHomePostsByAllCommunities(feedSettings, since, newThreadSince) @@ -83,75 +80,14 @@ class HomeOutboxEventsEoseManager( // Drop the kinds the user turned off in Settings › Home from every home relay filter, so a // disabled group is never downloaded regardless of which top-nav strategy built the filters. - return base.removeDisabledHomeKinds(HomeFeedType.disabledKinds(key.account.settings.enabledHomeFeedTypes.value)) + return base.removeDisabledHomeKinds(HomeFeedType.disabledKinds(key.enabledHomeFeedTypes.value)) } - override fun user(key: HomeQueryState) = key.account.userProfile() - - override fun list(key: HomeQueryState) = key.listName() - - fun HomeQueryState.listNameFlow() = account.settings.defaultHomeFollowList - - fun HomeQueryState.listName() = listNameFlow().value - - fun HomeQueryState.followRelayFlow() = account.liveHomeFollowListsPerRelay - - fun HomeQueryState.followsPerRelay() = followRelayFlow().value - - val userJobMap = mutableMapOf>() - - @OptIn(FlowPreview::class) - override fun newSub(key: HomeQueryState): Subscription { - val user = user(key) - userJobMap[user]?.forEach { it.cancel() } - userJobMap[user] = - listOf( - key.scope.launch(Dispatchers.IO) { - key.listNameFlow().collectLatest { - invalidateFilters() - } - }, - key.scope.launch(Dispatchers.IO) { - key.followRelayFlow().sample(1000).collectLatest { - invalidateFilters() - } - }, - key.scope.launch(Dispatchers.IO) { - // Re-arm the home subscriptions when a content-type toggle flips, so a disabled - // group leaves the live REQ and a re-enabled one comes back without a restart. - key.account.settings.enabledHomeFeedTypes - .drop(1) - .collectLatest { invalidateFilters() } - }, - key.account.scope.launch(Dispatchers.IO) { - key.feedState.homeNewThreads.lastNoteCreatedAtWhenFullyLoaded.sample(5000).collectLatest { - invalidateFilters() - } - }, - key.account.scope.launch(Dispatchers.IO) { - key.feedState.homeReplies.lastNoteCreatedAtWhenFullyLoaded.sample(5000).collectLatest { - invalidateFilters() - } - }, - ) - - return super.newSub(key) - } - - override fun endSub( - key: User, - subId: String, - ) { - super.endSub(key, subId) - userJobMap[key]?.forEach { it.cancel() } - } + // Re-arm the home subscriptions when a content-type toggle flips, so a disabled group leaves the + // live REQ and a re-enabled one comes back without a restart. + override fun extraInvalidators(key: HomeQueryState): List> = listOf(key.enabledHomeFeedTypes.drop(1)) } -/** - * Removes the [disabled] kinds from each home filter. A filter with no `kinds` (e.g. an - * algo-feed id/address fetch) is left untouched; a filter whose kinds all become disabled is - * dropped entirely, since sending it with an empty `kinds` would wrongly match every kind. - */ private fun List.removeDisabledHomeKinds(disabled: Set): List { if (disabled.isEmpty()) return this return mapNotNull { relayFilter -> diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip72Communities/FilterHomePostsByAllCommunities.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip72Communities/FilterHomePostsByAllCommunities.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip72Communities/FilterHomePostsByAllCommunities.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip72Communities/FilterHomePostsByAllCommunities.kt index d4c0118a63..1fc81a1b93 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip72Communities/FilterHomePostsByAllCommunities.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip72Communities/FilterHomePostsByAllCommunities.kt @@ -18,7 +18,7 @@ * 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.amethyst.ui.screen.loggedIn.home.datasource.nip72Communities +package com.vitorpamplona.amethyst.commons.relayClient.home.nip72Communities import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.allcommunities.AllCommunitiesTopNavPerRelayFilterSet import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip72Communities/FilterHomePostsFromCommunities.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip72Communities/FilterHomePostsFromCommunities.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip72Communities/FilterHomePostsFromCommunities.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip72Communities/FilterHomePostsFromCommunities.kt index c4c892f924..4b8a2250bb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip72Communities/FilterHomePostsFromCommunities.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip72Communities/FilterHomePostsFromCommunities.kt @@ -18,7 +18,7 @@ * 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.amethyst.ui.screen.loggedIn.home.datasource.nip72Communities +package com.vitorpamplona.amethyst.commons.relayClient.home.nip72Communities import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.community.SingleCommunityTopNavPerRelayFilterSet import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip90AlgoFeeds/FilterHomePostsByAlgoFeedIds.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip90AlgoFeeds/FilterHomePostsByAlgoFeedIds.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip90AlgoFeeds/FilterHomePostsByAlgoFeedIds.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip90AlgoFeeds/FilterHomePostsByAlgoFeedIds.kt index 7cf31d0930..d8dbc554ab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip90AlgoFeeds/FilterHomePostsByAlgoFeedIds.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip90AlgoFeeds/FilterHomePostsByAlgoFeedIds.kt @@ -18,7 +18,7 @@ * 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.amethyst.ui.screen.loggedIn.home.datasource.nip90AlgoFeeds +package com.vitorpamplona.amethyst.commons.relayClient.home.nip90AlgoFeeds import com.vitorpamplona.amethyst.commons.model.topNavFeeds.favoriteAlgoFeeds.FavoriteAlgoFeedTopNavPerRelayFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.favoriteAlgoFeeds.FavoriteAlgoFeedTopNavPerRelayFilterSet diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/napplets/ConnectedAppsFilterAssembler.kt similarity index 86% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/napplets/ConnectedAppsFilterAssembler.kt index a3770c904c..141b811ab1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/napplets/ConnectedAppsFilterAssembler.kt @@ -18,24 +18,29 @@ * 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.amethyst.ui.screen.loggedIn.napplets.datasource +package com.vitorpamplona.amethyst.commons.relayClient.napplets import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.model.IAccount import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager import com.vitorpamplona.amethyst.commons.relayClient.napplets.NappletsFilterAssembler -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import kotlinx.coroutines.flow.StateFlow /** * Keyspace for the connected-apps manifest subscription. Carries the account (for relay selection) * and the specific authors whose napplet manifests should be fetched — the set of pubkeys that have * been granted permissions in the user's ledger. + * + * @param homeRelays the user's home (read) relays, where the connected apps' manifests are fetched. */ class ConnectedAppsQueryState( - override val account: Account, + override val account: IAccount, val authors: Set, + val homeRelays: StateFlow>, ) : AccountScopedQuery /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsSubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/napplets/ConnectedAppsSubAssembler.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsSubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/napplets/ConnectedAppsSubAssembler.kt index 0ef9f19a7f..38cf60cdef 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsSubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/napplets/ConnectedAppsSubAssembler.kt @@ -18,7 +18,7 @@ * 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.amethyst.ui.screen.loggedIn.napplets.datasource +package com.vitorpamplona.amethyst.commons.relayClient.napplets import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager import com.vitorpamplona.amethyst.commons.relayClient.napplets.filterNappletsByAuthors @@ -43,7 +43,7 @@ class ConnectedAppsSubAssembler( since: SincePerRelayMap?, ): List { if (key.authors.isEmpty()) return emptyList() - val relays = key.account.homeRelays.flow.value + val relays = key.homeRelays.value if (relays.isEmpty()) return emptyList() return relays.flatMap { relay -> filterNappletsByAuthors(relay, key.authors, since?.get(relay)?.time) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/subassembies/ThreadEventLoaderSubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/thread/ThreadEventLoaderSubAssembler.kt similarity index 82% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/subassembies/ThreadEventLoaderSubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/thread/ThreadEventLoaderSubAssembler.kt index e20a7df4a9..d3de03e6cb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/subassembies/ThreadEventLoaderSubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/thread/ThreadEventLoaderSubAssembler.kt @@ -18,14 +18,13 @@ * 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.amethyst.ui.screen.loggedIn.threadview.datasources.subassembies +package com.vitorpamplona.amethyst.commons.relayClient.thread import com.vitorpamplona.amethyst.commons.model.ThreadAssembler +import com.vitorpamplona.amethyst.commons.model.cache.ICacheProvider import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEoseManager import com.vitorpamplona.amethyst.commons.relayClient.thread.filterMissingEventsForThread import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.LocalCache -import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources.ThreadQueryState import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter @@ -40,6 +39,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter * saves the of the thread EOSEs in the long run to avoid re-downloading */ class ThreadEventLoaderSubAssembler( + val cache: ICacheProvider, client: INostrClient, allKeys: () -> Set, ) : PerUniqueIdEoseManager(client, allKeys, invalidateAfterEose = true) { @@ -47,9 +47,9 @@ class ThreadEventLoaderSubAssembler( key: ThreadQueryState, since: SincePerRelayMap?, ): List? { - val branches = ThreadAssembler(LocalCache).findThreadFor(key.eventId) ?: return null - val defaultRelays = key.account.followPlusAllMineWithSearch.flow.value - return filterMissingEventsForThread(LocalCache, branches, defaultRelays) + val branches = ThreadAssembler(cache).findThreadFor(key.eventId) ?: return null + val defaultRelays = key.defaultRelays.value + return filterMissingEventsForThread(cache, branches, defaultRelays) } override fun id(key: ThreadQueryState) = key.eventId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/ThreadFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/thread/ThreadFilterAssembler.kt similarity index 69% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/ThreadFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/thread/ThreadFilterAssembler.kt index 2e709600f3..857133da92 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/ThreadFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/thread/ThreadFilterAssembler.kt @@ -18,32 +18,41 @@ * 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.amethyst.ui.screen.loggedIn.threadview.datasources +package com.vitorpamplona.amethyst.commons.relayClient.thread import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.model.IAccount +import com.vitorpamplona.amethyst.commons.model.cache.ICacheProvider import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources.subassembies.ThreadEventLoaderSubAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources.subassembies.ThreadFilterSubAssembler import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import kotlinx.coroutines.flow.StateFlow -// This allows multiple screen to be listening to tags, even the same tag +/** + * One screen's interest in a thread. Several screens may open the same thread at once, each with + * its own key. + * + * @param defaultRelays follows' outboxes plus the user's relays and search relays: the fallback set + * asked for a thread event that no relay hint resolves. + */ @Stable class ThreadQueryState( val eventId: HexKey, - override val account: Account, + override val account: IAccount, + val defaultRelays: StateFlow>, ) : AccountScopedQuery @Stable class ThreadFilterAssembler( + cache: ICacheProvider, client: INostrClient, ) : ComposeSubscriptionManager() { val group = listOf( - ThreadFilterSubAssembler(client, ::allKeys), - ThreadEventLoaderSubAssembler(client, ::allKeys), + ThreadFilterSubAssembler(cache, client, ::allKeys), + ThreadEventLoaderSubAssembler(cache, client, ::allKeys), ) override fun invalidateKeys() = invalidateFilters() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/subassembies/ThreadFilterSubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/thread/ThreadFilterSubAssembler.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/subassembies/ThreadFilterSubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/thread/ThreadFilterSubAssembler.kt index cd26d02df2..1a70dcfc27 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/subassembies/ThreadFilterSubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/thread/ThreadFilterSubAssembler.kt @@ -18,14 +18,13 @@ * 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.amethyst.ui.screen.loggedIn.threadview.datasources.subassembies +package com.vitorpamplona.amethyst.commons.relayClient.thread import com.vitorpamplona.amethyst.commons.model.ThreadAssembler +import com.vitorpamplona.amethyst.commons.model.cache.ICacheProvider import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEoseManager import com.vitorpamplona.amethyst.commons.relayClient.thread.filterEventsInThreadForRoot import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.LocalCache -import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources.ThreadQueryState import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter @@ -37,6 +36,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter * saves the of the thread EOSEs in the long run to avoid re-downloading */ class ThreadFilterSubAssembler( + val cache: ICacheProvider, client: INostrClient, allKeys: () -> Set, ) : PerUniqueIdEoseManager(client, allKeys) { @@ -44,7 +44,7 @@ class ThreadFilterSubAssembler( key: ThreadQueryState, since: SincePerRelayMap?, ): List? { - val root = ThreadAssembler(LocalCache).findRoot(key.eventId) ?: return null + val root = ThreadAssembler(cache).findRoot(key.eventId) ?: return null return filterEventsInThreadForRoot(root, since) } diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip90AlgoFeeds/FilterHomePostsByAlgoFeedIdsTest.kt b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip90AlgoFeeds/FilterHomePostsByAlgoFeedIdsTest.kt similarity index 96% rename from amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip90AlgoFeeds/FilterHomePostsByAlgoFeedIdsTest.kt rename to commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip90AlgoFeeds/FilterHomePostsByAlgoFeedIdsTest.kt index dccb0dc6b7..fd94ee87ee 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip90AlgoFeeds/FilterHomePostsByAlgoFeedIdsTest.kt +++ b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/relayClient/home/nip90AlgoFeeds/FilterHomePostsByAlgoFeedIdsTest.kt @@ -18,17 +18,17 @@ * 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.amethyst.ui.screen.loggedIn.home.datasource.nip90AlgoFeeds +package com.vitorpamplona.amethyst.commons.relayClient.home.nip90AlgoFeeds import com.vitorpamplona.amethyst.commons.model.topNavFeeds.favoriteAlgoFeeds.FavoriteAlgoFeedTopNavPerRelayFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.favoriteAlgoFeeds.FavoriteAlgoFeedTopNavPerRelayFilterSet import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip90Dvms.contentDiscoveryResponse.NIP90ContentDiscoveryResponseEvent import com.vitorpamplona.quartz.nip90Dvms.status.NIP90StatusEvent -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNotNull -import org.junit.Assert.assertTrue -import org.junit.Test +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertTrue class FilterHomePostsByAlgoFeedIdsTest { private val userRelay = RelayUrlNormalizer.normalizeOrNull("wss://user.example/")!!