fix(concord): list joined communities in Messages before they fold

Messages built Concord rows only from a folded Control Plane, so a community
whose planes had not loaded (just joined, a genesis that never landed, or a
relay that dropped it) had no row at all: no way to open it and no way to leave
it, which read as the community being lost. Such a community now gets its
community row in both view modes, titled with the name it was joined under
until its metadata folds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Vitor Pamplona
2026-09-29 14:59:06 -04:00
co-authored by Claude Opus 5.5
parent 07c1a7489e
commit f4688b5753
2 changed files with 21 additions and 11 deletions
@@ -1036,15 +1036,17 @@ private fun ConcordServerRoomCompose(
// Community name/icon from the folded Control Plane (bumped via the session revision).
val revision by accountViewModel.account.concordSessions.revision
.collectAsStateWithLifecycle()
val metadata =
val session =
remember(row.communityId, revision) {
accountViewModel.account.concordSessions
.sessionFor(row.communityId)
?.state
?.value
?.metadata
accountViewModel.account.concordSessions.sessionFor(row.communityId)
}
val name = metadata?.name?.takeIf { it.isNotBlank() } ?: stringRes(Res.string.concord_home_title)
val metadata = remember(session, revision) { session?.state?.value?.metadata }
// Before the Control Plane folds there is no metadata; the name the community was joined under
// still tells the user which one it is.
val name =
metadata?.name?.takeIf { it.isNotBlank() }
?: session?.entry?.name?.takeIf { it.isNotBlank() }
?: stringRes(Res.string.concord_home_title)
val author = row.newestMessage?.author
val noteEvent = row.newestMessage?.event
@@ -212,7 +212,11 @@ class ChatroomListKnownFeedFilter(
when (account.settings.concordViewMode.value) {
ConcordViewMode.INLINE ->
account.concordSessions.sessions().flatMap { session ->
val state = session.state.value ?: return@flatMap emptyList<Note>()
// Not folded yet (just joined, or its Control Plane never arrived): no
// channels to list, so show the community itself. Skipping it made a
// community whose genesis is missing invisible everywhere, with no way in
// and no way to leave it.
val state = session.state.value ?: return@flatMap listOf<Note>(ConcordServerRoomNote(session.entry.id, null))
state.channels.keys.map { channelIdHex ->
val channel = LocalCache.getOrCreateConcordChannel(ConcordChannelId(session.entry.id, channelIdHex))
channel.newestConcordNote(account) ?: channel.placeholderNote()
@@ -221,10 +225,14 @@ class ChatroomListKnownFeedFilter(
ConcordViewMode.GROUPED ->
// One row per joined community, carrying the newest message across ALL its channels.
account.concordSessions.sessions().mapNotNull { session ->
val state = session.state.value ?: return@mapNotNull null
account.concordSessions.sessions().map { session ->
// An unfolded community still gets its row (see INLINE above).
val state = session.state.value
val newest =
state.channels.keys
state
?.channels
?.keys
.orEmpty()
.mapNotNull { LocalCache.getOrCreateConcordChannel(ConcordChannelId(session.entry.id, it)).newestConcordNote(account) }
.maxByOrNull { it.createdAt() ?: 0L }
ConcordServerRoomNote(session.entry.id, newest)