From fc284e3cfe48b90e7eb8974016f619ca0636ce2a Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 19 Apr 2026 16:43:46 +0000 Subject: [PATCH] feat(dvm-favorites): rename user-facing to "Favorite Feed Algorithms" + fix cold-start race MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - User-facing rename. All user-visible strings switch from "favourite" to "favorite" (American spelling) and from "DVM(s)" to "Feed Algorithm(s)": settings entry, spinner group label, empty state, banner messages, menu accessibility labels. Code identifiers still reference NIP-90's "DVM" protocol name since that's the wire spec. - Cold-start race. When the app relaunches with a persisted TopFilter.FavoriteDvm, the AppDefinitionEvent may not be in cache yet. mergeInterests was filtering out any favorite whose AppDefinitionEvent didn't yet advertise kind 5300, so the spinner didn't include a chip matching the persisted selection — it showed "Select an option" while the orchestrator quietly fired the RPC with no UI to ground it. Always include every favorite; the 5300 check at add time (in FavoriteDvmToggle) is enough. --- .../model/dvms/FavoriteDvmOrchestrator.kt | 4 ++-- .../favoriteDvm/AllFavoriteDvmsFeedFlow.kt | 4 ++-- .../AllFavoriteDvmsTopNavFilter.kt | 2 +- .../favoriteDvm/FavoriteDvmTopNavFilter.kt | 2 +- .../FavoriteDvmTopNavPerRelayFilterSet.kt | 4 ++-- .../amethyst/ui/screen/TopNavFilterState.kt | 21 ++++++++----------- .../nip90Dvms/FilterHomePostsByDvmIds.kt | 2 +- amethyst/src/main/res/values/strings.xml | 18 ++++++++-------- 8 files changed, 27 insertions(+), 30 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/dvms/FavoriteDvmOrchestrator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/dvms/FavoriteDvmOrchestrator.kt index ddf24813a..860cdfd0e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/dvms/FavoriteDvmOrchestrator.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/dvms/FavoriteDvmOrchestrator.kt @@ -45,7 +45,7 @@ import kotlinx.coroutines.sync.withLock private const val RESPONSE_TIMEOUT_MS = 20_000L /** - * Immutable snapshot of a favourite DVM's current request/response state. + * Immutable snapshot of a favorite DVM's current request/response state. * * - [requestId] is the id of the most recently published kind-5300 request. * - [responseRelays] is the relay set the kind-5300 was sent to — the same set on @@ -65,7 +65,7 @@ data class FavoriteDvmSnapshot( ) /** - * Manages the NIP-90 content-discovery RPC cycle for each favourite DVM the user + * Manages the NIP-90 content-discovery RPC cycle for each favorite DVM the user * pins to the top-nav. * * The orchestrator is lazy: it starts a request/response cycle the first time any diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/AllFavoriteDvmsFeedFlow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/AllFavoriteDvmsFeedFlow.kt index 8f880a4b1..c35c2ba72 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/AllFavoriteDvmsFeedFlow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/AllFavoriteDvmsFeedFlow.kt @@ -34,9 +34,9 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest /** - * Feed flow that merges snapshots from every currently-favourited DVM into a + * Feed flow that merges snapshots from every currently-favorited DVM into a * single [AllFavoriteDvmsTopNavFilter]. Re-wires subscriptions whenever the - * favourite set changes. + * favorite set changes. */ class AllFavoriteDvmsFeedFlow( val favoriteDvmAddresses: StateFlow>, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/AllFavoriteDvmsTopNavFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/AllFavoriteDvmsTopNavFilter.kt index f686bec2b..36e7e6b6f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/AllFavoriteDvmsTopNavFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/AllFavoriteDvmsTopNavFilter.kt @@ -32,7 +32,7 @@ import kotlinx.coroutines.flow.MutableStateFlow /** * Top-nav filter that unions the latest kind-6300 responses from every currently - * favourited DVM. Behaves like [FavoriteDvmTopNavFilter] (pure membership check + * favorited DVM. Behaves like [FavoriteDvmTopNavFilter] (pure membership check * against a snapshot), but the accepted set is the union across N DVMs and the * request-id list carries one entry per DVM for the relay-listen subscription. */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/FavoriteDvmTopNavFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/FavoriteDvmTopNavFilter.kt index 88924a2a4..9534bc1c8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/FavoriteDvmTopNavFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/FavoriteDvmTopNavFilter.kt @@ -32,7 +32,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow /** - * Top-nav filter backed by the latest kind-6300 response from a favourite DVM. + * Top-nav filter backed by the latest kind-6300 response from a favorite DVM. * * The filter is a pure immutable membership check: [match] accepts a note only if the * DVM's latest response included it. When a new response arrives, a new instance is diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/FavoriteDvmTopNavPerRelayFilterSet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/FavoriteDvmTopNavPerRelayFilterSet.kt index 399d2ab31..318840384 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/FavoriteDvmTopNavPerRelayFilterSet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteDvm/FavoriteDvmTopNavPerRelayFilterSet.kt @@ -32,8 +32,8 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl * - [listenRelays] — the union of DVM publish relays across all active DVMs * (where they will deliver future kind 6300 / 7000 events for their requests). * - [requestIds] — the set of currently-active kind-5300 request ids to listen - * for. A single-DVM filter carries one; the merged "All favourite DVMs" - * filter carries one per favourite DVM. + * for. A single-DVM filter carries one; the merged "All favorite DVMs" + * filter carries one per favorite DVM. */ class FavoriteDvmTopNavPerRelayFilterSet( val contentFetches: Map, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/TopNavFilterState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/TopNavFilterState.kt index 7d2003e85..7b65a43e1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/TopNavFilterState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/TopNavFilterState.kt @@ -35,7 +35,6 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent import com.vitorpamplona.quartz.nip51Lists.peopleList.PeopleListEvent import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent -import com.vitorpamplona.quartz.nip90Dvms.contentDiscoveryRequest.NIP90ContentDiscoveryRequestEvent import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @@ -182,24 +181,22 @@ class TopNavFilterState( ) } - // Only DVMs that advertise NIP-90 content discovery (kind 5300) can produce a - // home feed. Hide entries whose AppDefinitionEvent isn't loaded yet OR doesn't - // include kind 5300 so the chip doesn't appear for image-generation, translation, - // search, or other DVM kinds that would never reply. + // Favorites can only be added through FavoriteDvmToggle, which itself checks + // that the AppDefinitionEvent advertises kind 5300. Don't re-check here: on + // cold start the AppDefinitionEvent may not be in cache yet, and dropping + // the entry means the persisted TopFilter.FavoriteDvm can't find its chip + // in the spinner (user sees "Select an option" while the banner fires the + // RPC — the bug we had before this change). val favoriteDvms = - favoriteDvmList.mapNotNull { dvmNote -> - val supports5300 = - (dvmNote.event as? AppDefinitionEvent) - ?.includeKind(NIP90ContentDiscoveryRequestEvent.KIND) == true - if (!supports5300) return@mapNotNull null + favoriteDvmList.map { dvmNote -> FeedDefinition( TopFilter.FavoriteDvm(dvmNote.address), FavoriteDvmName(dvmNote), ) } - // Only show the "All favourite DVMs" meta-chip when there is at least one - // real favourite to merge; otherwise the chip opens to an empty feed. + // Only show the "All favorite DVMs" meta-chip when there is at least one + // real favorite to merge; otherwise the chip opens to an empty feed. val allFavorites = if (favoriteDvms.isNotEmpty()) listOf(allFavoriteDvmsFollow) else emptyList() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip90Dvms/FilterHomePostsByDvmIds.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip90Dvms/FilterHomePostsByDvmIds.kt index 57afdd401..c042199a6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip90Dvms/FilterHomePostsByDvmIds.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/nip90Dvms/FilterHomePostsByDvmIds.kt @@ -31,7 +31,7 @@ import com.vitorpamplona.quartz.nip90Dvms.contentDiscoveryResponse.NIP90ContentD import com.vitorpamplona.quartz.nip90Dvms.status.NIP90StatusEvent /** - * Builds relay REQ filters for a favourite-DVM home feed. + * Builds relay REQ filters for a favorite-DVM home feed. * * Two distinct subscription kinds with two distinct relay sets: * diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index cbd3e0154..9a6ce629f 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -1728,20 +1728,20 @@ Locations Communities Lists - DVMs - All favourite DVMs + Feed Algorithms + All favorite feed algorithms Relays - Add DVM to favorites + Add feed algorithm to favorites Remove from favorites - Favourite DVMs - Content-discovery DVMs you starred here appear as filter chips on the Home feed. Open Discover to add more. - No favourite DVMs yet. Open Discover, tap a content-discovery DVM, and star it to add it here. + Favorite Feed Algorithms + Feed algorithms you starred here appear as filter chips on the Home feed. Open Discover to add more. + No favorite feed algorithms yet. Open Discover, tap one, and star it to add it here. Asking %1$s for a feed… - Asking your favourite DVMs for feeds… + Asking your favorite feed algorithms for feeds… Processing your feed… - This DVM requires payment - DVM returned an error + This feed algorithm requires payment + The feed algorithm returned an error Retry Log off on device lock