feat(nests): hide rooms with no fresh speakers from drawer feed
Adds hasFreshSpeakers gate to NestsFeedFilter so OPEN/PRIVATE rooms whose live speaker slate is empty are dropped — a room with no fresh kind-10312 presence carrying onstage=1 has effectively ended even if its kind-30312 status still says live.
This commit is contained in:
+32
@@ -91,6 +91,7 @@ class NestsFeedFilter(
|
|||||||
if (!hasMinimumNestFields(noteEvent)) return@filterTo false
|
if (!hasMinimumNestFields(noteEvent)) return@filterTo false
|
||||||
if (!isWithinPlannedWindow(noteEvent, now)) return@filterTo false
|
if (!isWithinPlannedWindow(noteEvent, now)) return@filterTo false
|
||||||
if (!isLiveByPresence(noteEvent, presenceCutoff)) return@filterTo false
|
if (!isLiveByPresence(noteEvent, presenceCutoff)) return@filterTo false
|
||||||
|
if (!hasFreshSpeakers(noteEvent, presenceCutoff)) return@filterTo false
|
||||||
|
|
||||||
if (filterParams.match(noteEvent, it.relays)) return@filterTo true
|
if (filterParams.match(noteEvent, it.relays)) return@filterTo true
|
||||||
|
|
||||||
@@ -181,6 +182,37 @@ class NestsFeedFilter(
|
|||||||
return fresh
|
return fresh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drop OPEN/PRIVATE rooms whose live speaker slate is empty. A room
|
||||||
|
* with no fresh kind-10312 presence carrying `onstage=1` has no one
|
||||||
|
* left on stage — even if the kind-30312 status still says `live`,
|
||||||
|
* there is nothing to listen to and the room has effectively ended.
|
||||||
|
*
|
||||||
|
* Same created-at grace as [isLiveByPresence] so brand-new rooms
|
||||||
|
* surface before the first speaker heartbeat arrives. CLOSED and
|
||||||
|
* PLANNED rooms bypass this gate for the same reasons listed on
|
||||||
|
* [isLiveByPresence].
|
||||||
|
*/
|
||||||
|
private fun hasFreshSpeakers(
|
||||||
|
event: MeetingSpaceEvent,
|
||||||
|
presenceCutoff: Long,
|
||||||
|
): Boolean {
|
||||||
|
val status = event.status()
|
||||||
|
if (status != StatusTag.STATUS.LIVE && status != StatusTag.STATUS.PRIVATE) return true
|
||||||
|
if (event.createdAt > presenceCutoff) return true
|
||||||
|
|
||||||
|
val channel = LocalCache.getLiveActivityChannelIfExists(event.address()) ?: return false
|
||||||
|
var hasSpeaker = false
|
||||||
|
channel.notes.forEach { _, note ->
|
||||||
|
if (hasSpeaker) return@forEach
|
||||||
|
val e = note.event
|
||||||
|
if (e is MeetingRoomPresenceEvent && e.createdAt > presenceCutoff && e.onstage() == true) {
|
||||||
|
hasSpeaker = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasSpeaker
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Author set used for p-tag follow expansion. Returns null for
|
* Author set used for p-tag follow expansion. Returns null for
|
||||||
* top filters where expansion is not meaningful (mute/block, the
|
* top filters where expansion is not meaningful (mute/block, the
|
||||||
|
|||||||
Reference in New Issue
Block a user