diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/AcceptedByRelaysGallery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/AcceptedByRelaysGallery.kt index 01d75014c0..b0e29acd7b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/AcceptedByRelaysGallery.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/AcceptedByRelaysGallery.kt @@ -29,7 +29,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue +import androidx.compose.runtime.State import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -56,18 +56,14 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.sample /** - * The "accepted by relays" line of the reaction gallery: the favicon of every relay - * the note was seen on. This is the same relay-pill set that Complete UI Mode used to - * paint below the author avatar; it now lives in the expanded reaction gallery so it - * is available to everyone, not just Complete mode. + * Observes the relays the note was seen on, throttled and de-duplicated for the + * "accepted by relays" gallery line. Exposed as State so the caller can both gate + * the gallery's visibility on it and feed it to [RenderAcceptedByRelaysGallery] + * from a single subscription. */ @OptIn(FlowPreview::class) @Composable -internal fun WatchRelaysAndRenderGallery( - baseNote: Note, - nav: INav, - accountViewModel: AccountViewModel, -) { +internal fun observeNoteRelays(baseNote: Note): State> { // Cold wrapper: `flow()` must be re-resolved on every collection start. A memory // trim destroys the NoteFlowSet while the lifecycle is stopped; a stateFlow // captured in remember would then be orphaned and never see another relay update. @@ -81,15 +77,17 @@ internal fun WatchRelaysAndRenderGallery( } val initial = remember(baseNote) { baseNote.relays.toImmutableList() } - val relays by flow.collectAsStateWithLifecycle(initial) - - if (relays.isNotEmpty()) { - RenderAcceptedByRelaysGallery(relays, nav, accountViewModel) - } + return flow.collectAsStateWithLifecycle(initial) } +/** + * The "accepted by relays" line of the reaction gallery: the favicon of every relay + * the note was seen on. This is the same relay-pill set that Complete UI Mode used to + * paint below the author avatar; it now lives in the expanded reaction gallery so it + * is available to everyone, not just Complete mode. + */ @Composable -private fun RenderAcceptedByRelaysGallery( +internal fun RenderAcceptedByRelaysGallery( relays: ImmutableList, nav: INav, accountViewModel: AccountViewModel, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index cbc89c4e63..46aaad443c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -563,22 +563,28 @@ private fun ReactionDetailGallery( val defaultBackgroundColor = MaterialTheme.colorScheme.background val backgroundColor = remember { mutableStateOf(defaultBackgroundColor) } - // Keep subscribing for reaction/zap/boost arrivals, but no longer gate the gallery - // on them: the "accepted by relays" line is (almost) always present, so once the - // user expands the gallery there is always at least that line to show. - observeNoteReferences(baseNote, accountViewModel) + val hasReactions by observeNoteReferences(baseNote, accountViewModel) + val relays by observeNoteRelays(baseNote) - Row( - verticalAlignment = CenterVertically, - modifier = Modifier.padding(start = 10.dp, top = 5.dp), - ) { - Column { - WatchRelaysAndRenderGallery(baseNote, nav, accountViewModel) - WatchZapAndRenderGallery(baseNote, backgroundColor, nav, accountViewModel) - WatchNutzapsAndRenderGallery(baseNote, nav, accountViewModel) - WatchOnchainZapsAndRenderGallery(baseNote, nav, accountViewModel) - WatchBoostsAndRenderGallery(baseNote, nav, accountViewModel) - WatchReactionsAndRenderGallery(baseNote, nav, accountViewModel) + // The gallery shows whenever there is anything to display: the "accepted by relays" + // line (relays are almost always present once a note is seen) or any zap/boost/ + // reaction line. Guarding here keeps the padded Row from rendering an empty strip + // for a note that has neither. + if (hasReactions || relays.isNotEmpty()) { + Row( + verticalAlignment = CenterVertically, + modifier = Modifier.padding(start = 10.dp, top = 5.dp), + ) { + Column { + if (relays.isNotEmpty()) { + RenderAcceptedByRelaysGallery(relays, nav, accountViewModel) + } + WatchZapAndRenderGallery(baseNote, backgroundColor, nav, accountViewModel) + WatchNutzapsAndRenderGallery(baseNote, nav, accountViewModel) + WatchOnchainZapsAndRenderGallery(baseNote, nav, accountViewModel) + WatchBoostsAndRenderGallery(baseNote, nav, accountViewModel) + WatchReactionsAndRenderGallery(baseNote, nav, accountViewModel) + } } } }