refactor(nests): keep room presence out of channel.notes entirely

Presence (kind-10312) was being stored in both `channel.notes` and the
`presenceNotes` index. The mixed-kind `notes` map is dominated by chat
in active rooms, and only HomeLiveFilter still read presence from it --
which is now migrated to scan presenceNotes directly.

- LocalCache.consume(MeetingRoomPresenceEvent): drop the `channel.addNote`
  call; only addPresenceNote, plus addRelay so the channel's relay-counter
  still tracks where presence arrived from.
- LiveActivitiesChannel: addPresenceNote / removePresenceNote emit on
  flowSet.notes so reactive observers (NestsFeedLoaded) still update.
- HomeLiveFilter.shouldIncludeChannel: scan presenceNotes separately for
  follow-broadcast detection in audio rooms (chat scan unchanged).
- HomeLiveFilter.followsThatParticipateOn: also count presenceNotes
  authors so audio-room hosts/speakers factor into the participation
  sort even when they haven't chatted.
- ChannelFeedFilter: delete the isChatEvent workaround that was excluding
  presence from the chat feed -- presence no longer lands there.
This commit is contained in:
Claude
2026-04-30 13:19:20 +00:00
parent 7845072f20
commit 566133750b
4 changed files with 52 additions and 46 deletions
@@ -49,15 +49,22 @@ class LiveActivitiesChannel(
* unbounded the way `notes` does. Empty for streaming channels
* (kind-30311) — only kind-30312 rooms publish presence.
*
* Lets feeds answer "is anyone live on stage in this room?"
* without scanning the chat-dominated `notes` map. See
* [com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.dal.NestsFeedFilter].
* Presence lives ONLY here, not in the base `notes` map: the
* mixed-kind `notes` is dominated by chat in active rooms and
* iterating it just to find presence is wasteful. Feeds that need
* "is anyone live on stage in this room?" iterate this index
* directly. See
* [com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.dal.NestsFeedFilter]
* and [com.vitorpamplona.amethyst.ui.screen.loggedIn.home.dal.HomeLiveFilter].
*/
val presenceNotes = LargeCache<HexKey, Note>()
fun addPresenceNote(note: Note) {
val author = note.author?.pubkeyHex ?: return
val previous = presenceNotes.get(author)
if (previous?.idHex == note.idHex) return
presenceNotes.put(author, note)
flowSet?.notes?.invalidateData()
}
/**
@@ -68,7 +75,9 @@ class LiveActivitiesChannel(
* freshness window.
*/
fun removePresenceNote(author: HexKey) {
if (!presenceNotes.containsKey(author)) return
presenceNotes.remove(author)
flowSet?.notes?.invalidateData()
}
fun address() = address