diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordUnread.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordUnread.kt index 4bcbfef652..5f5b6124ef 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordUnread.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordUnread.kt @@ -31,6 +31,7 @@ import com.vitorpamplona.quartz.nip22Comments.CommentEvent import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf @@ -72,22 +73,29 @@ fun concordChannelUnreadCountFlow( fun concordCommunityHasUnreadFlow( account: Account, communityId: String, -): Flow { - val session = account.concordSessions.sessionFor(communityId) ?: return flowOf(false) - return session.state.flatMapLatest { state -> - val channelKeys = - state - ?.channels - ?.keys - ?.toList() - .orEmpty() - if (channelKeys.isEmpty()) { - flowOf(false) - } else { - combine(channelKeys.map { concordChannelUnreadCountFlow(account, communityId, it) }) { counts -> counts.any { it > 0 } } - } - } -} +): Flow = + // Re-resolve the session on every revision tick rather than capturing it once. A Refounding + // rebuilds a still-joined community's session in place (same id, new object) and a fold changes + // the channel set — both bump `revision`; capturing the session once would leave the fan-in + // pointed at a dead session so the dot freezes. This mirrors how ConcordServerRoomCompose already + // re-reads the row's name/icon off `revision`. + account.concordSessions.revision + .flatMapLatest { + val channelKeys = + account.concordSessions + .sessionFor(communityId) + ?.state + ?.value + ?.channels + ?.keys + ?.toList() + .orEmpty() + if (channelKeys.isEmpty()) { + flowOf(false) + } else { + combine(channelKeys.map { concordChannelUnreadCountFlow(account, communityId, it) }) { counts -> counts.any { it > 0 } } + } + }.distinctUntilChanged() /** * True for a note the Concord channel *timeline* actually renders — the same predicate as diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupUnread.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupUnread.kt index 60ab012f9c..75659f454e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupUnread.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupUnread.kt @@ -30,6 +30,7 @@ import com.vitorpamplona.quartz.nip29RelayGroups.isGroupChatContent import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf @@ -64,17 +65,18 @@ fun relayGroupServerHasUnreadFlow( account: Account, relay: NormalizedRelayUrl, ): Flow = - account.relayGroupList.liveRelayGroupList.flatMapLatest { tags -> - val groupIds = - tags.mapNotNull { tag -> - if (RelayUrlNormalizer.normalizeOrNull(tag.relayUrl) == relay) GroupId(tag.groupId, relay) else null + account.relayGroupList.liveRelayGroupList + .flatMapLatest { tags -> + val groupIds = + tags.mapNotNull { tag -> + if (RelayUrlNormalizer.normalizeOrNull(tag.relayUrl) == relay) GroupId(tag.groupId, relay) else null + } + if (groupIds.isEmpty()) { + flowOf(false) + } else { + combine(groupIds.map { relayGroupChannelHasUnreadFlow(account, it) }) { perGroup -> perGroup.any { it } } } - if (groupIds.isEmpty()) { - flowOf(false) - } else { - combine(groupIds.map { relayGroupChannelHasUnreadFlow(account, it) }) { perGroup -> perGroup.any { it } } - } - } + }.distinctUntilChanged() /** Whether this group's message store holds any acceptable chat content created after [sinceSecs]. */ private fun RelayGroupChannel.hasChatNewerThan(