fix: remove expired polls from notification cards via periodic re-evaluation

The open polls notification flow only re-evaluated when new notes arrived
or dismissed IDs changed. Polls that passed their close date remained
visible until something else triggered the flow. Adding a 1-minute ticker
to the combine ensures expired polls are filtered out promptly.

https://claude.ai/code/session_01VY9FRuzHzwTVrePaJiHuHx
This commit is contained in:
Claude
2026-04-06 02:33:49 +00:00
parent a1c7d956ff
commit 7d0a234fd8
@@ -29,12 +29,14 @@ import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent
import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.TimeUtils
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlin.time.Duration.Companion.minutes
@Stable @Stable
class OpenPollsState( class OpenPollsState(
@@ -47,14 +49,23 @@ class OpenPollsState(
authors = listOf(account.pubKey), authors = listOf(account.pubKey),
) )
// Periodic ticker to re-evaluate polls after their close date passes
private val ticker =
flow {
while (true) {
emit(Unit)
delay(1.minutes)
}
}
val flow: StateFlow<List<Note>> = val flow: StateFlow<List<Note>> =
combine( combine(
account.cache account.cache
.observeNotes(filter) .observeNotes(filter),
.map { notes -> filterOpenPolls(notes) },
account.settings.dismissedPollNoteIds, account.settings.dismissedPollNoteIds,
) { polls, dismissed -> ticker,
polls.filter { it.idHex !in dismissed } ) { notes, dismissed, _ ->
filterOpenPolls(notes).filter { it.idHex !in dismissed }
}.flowOn(Dispatchers.IO) }.flowOn(Dispatchers.IO)
.stateIn( .stateIn(
scope, scope,