fix(dvm-favorites): star click is a no-op + star missing from DVM detail top bar

Two distinct bugs with the same symptom ("clicking the star doesn't
seem to do anything"):

1. LocalCache didn't know how to route kind 10090. FavoriteDvmListEvent
   was missing from LocalCache's event-type dispatch, so after
   Account.followFavoriteDvm signs and publishes the event, the
   cache silently dropped it — never updated favoriteDvmListNote,
   so account.favoriteDvmList.flow never re-emitted, so the star's
   filled/outlined state (and the spinner chip) never flipped. Add
   `is FavoriteDvmListEvent -> consumeBaseReplaceable(...)`.

2. DvmTopBar's toggle never rendered. The Home feed passes the DVM's
   hex event id via Route.ContentDiscovery, so LoadNote(baseNoteHex)
   returns a plain Note, not the AddressableNote the toggle needs
   (the `is AddressableNote` guard was always false). Derive the
   AddressableNote from the loaded AppDefinitionEvent.address() so
   the toggle shows up with the correct backing object.
This commit is contained in:
Claude
2026-04-19 14:34:07 +00:00
parent 9ba2d2f5cc
commit d8b313088d
2 changed files with 22 additions and 6 deletions
@@ -149,6 +149,7 @@ import com.vitorpamplona.quartz.nip50Search.SearchRelayListEvent
import com.vitorpamplona.quartz.nip51Lists.PinListEvent
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.OldBookmarkListEvent
import com.vitorpamplona.quartz.nip51Lists.favoriteDvmList.FavoriteDvmListEvent
import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent
import com.vitorpamplona.quartz.nip51Lists.geohashList.GeohashListEvent
import com.vitorpamplona.quartz.nip51Lists.hashtagList.HashtagListEvent
@@ -2635,6 +2636,7 @@ object LocalCache : ILocalCache, ICacheProvider {
is LiveChessGameEndEvent -> consumeBaseReplaceable(event, relay, wasVerified)
is LiveChessDrawOfferEvent -> consumeBaseReplaceable(event, relay, wasVerified)
is HashtagListEvent -> consumeBaseReplaceable(event, relay, wasVerified)
is FavoriteDvmListEvent -> consumeBaseReplaceable(event, relay, wasVerified)
is HighlightEvent -> consumeRegularEvent(event, relay, wasVerified)
is IndexerRelayListEvent -> consumeBaseReplaceable(event, relay, wasVerified)
is InteractiveStoryPrologueEvent -> consumeBaseReplaceable(event, relay, wasVerified)
@@ -24,10 +24,12 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.style.TextOverflow
import com.vitorpamplona.amethyst.model.AddressableNote
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap
import com.vitorpamplona.amethyst.ui.components.LoadNote
import com.vitorpamplona.amethyst.ui.components.MyAsyncImage
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
@@ -37,6 +39,7 @@ import com.vitorpamplona.amethyst.ui.note.elements.BannerImage
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.SimpleImage35Modifier
import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent
@Composable
fun DvmTopBar(
@@ -87,12 +90,23 @@ fun DvmTopBar(
},
navigationIcon = { IconButton(onClick = nav::popBack) { ArrowBackIcon() } },
actions = {
// The route passes the event's hex id, so LoadNote returns a plain Note,
// not the AddressableNote the toggle needs. Derive the AddressableNote
// from the loaded AppDefinitionEvent's address() once the event exists.
LoadNote(baseNoteHex = appDefinitionId, accountViewModel = accountViewModel) { appDefinitionNote ->
if (appDefinitionNote is AddressableNote) {
FavoriteDvmToggle(
appDefinitionNote = appDefinitionNote,
accountViewModel = accountViewModel,
)
if (appDefinitionNote != null) {
val addressableNote by
observeNoteAndMap(appDefinitionNote, accountViewModel) { note ->
(note.event as? AppDefinitionEvent)?.let {
LocalCache.getOrCreateAddressableNote(it.address())
}
}
addressableNote?.let { target ->
FavoriteDvmToggle(
appDefinitionNote = target,
accountViewModel = accountViewModel,
)
}
}
}
},